/* Logiweb, a system for electronic distribution of mathematics Copyright (C) 2004-2008 Klaus Grue This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Klaus Grue, DIKU, Universitetsparken 1, DK2100 Copenhagen, Denmark, grue@diku.dk, http://logiweb.eu/, http://www.diku.dk/~grue/ Logiweb is a system for distribution of mathematical definitions, lemmas, and proofs. For more on Logiweb, consult http://logiweb.eu/. */ /********** * Config * **********/ #ifndef HEAPSIZE #define HEAPSIZE 10000000 #endif #ifndef STACKSIZE #define STACKSIZE 10000000 #endif #ifndef STORESIZE #define STORESIZE 10000 #endif #ifndef ALWAYSGC #define ALWAYSGC FALSE #endif /* Set STDREF to 0 when redefining patterns on each compilation */ #define STDREF 0 /* #define STDREF "015FD8C8D7F48AFF2A4035E38333BF24CCD3473C28BD9FC3BDF1ECAE0806" */ /************ * INCLUDES * ************/ #include #include #include #include #include #include #include #include #include #include #include #include #include /*********** * DEFINES * ***********/ /* cons(TAG_FALSE ,NIL ,NIL ) The constant F cons(TAG_INT ,val ,int ) Val is the least significant word of the integer cons(TAG_VECT ,bytes,vect ) Bytes are the least significant word of the vect cons(TAG_PAIR ,head ,tail ) Tagged pair cons(TAG_EX ,arg ,NIL ) Exception cons(TAG_MAP ,map ,info ) Tagged map. the 'info' is for the optimizer cons(TAG_OBJ ,tag ,val ) Object cons(TAG_GARB ,NIL ,NIL ) Garbage cons(TTAG_APPLY ,fct ,arg ) Functional applicationat term level cons(TTAG_LAMBDA ,term ,NIL ) Lambda abstraction at term level cons(TTAG_VAR ,index,NIL ) The variable with the given deBruijn index cons(TTAG_PAIR ,head ,tail ) Raw pairing at term level cons(TTAG_CONST ,rnf ,NIL ) A term whose value is the given rnf cons(TTAG_CALL ,term ,term*) Evaluate term in given term* environment cons(TTAG_ECALL ,eterm,term*) Evaluate eager term in given term* environment cons(MTAG_CLOSURE,term ,env ) Value of term in given closure* environment cons(MTAG_INDIR ,NIL ,rnf ) Indirection to the given rnf cons(MTAG_PAIR ,head ,tail ) Raw pairing at map level cons(MTAG_LAMBDA ,term ,env ) \x.term in given closure* environment cons(MTAG_FIX ,NIL ,NIL ) Fixed point operator Eager term tags: ETAG_var ETAG_ecall ETAG_digit0 " %0 ETAG_digit1 " %1 ETAG_digit2 " %2 ETAG_digit3 " %3 ETAG_digit4 " %4 ETAG_digit5 " %5 ETAG_digit6 " %6 ETAG_digit7 " %7 ETAG_digit8 " %8 ETAG_digit9 " %9 ETAG_times " * " ETAG_plus " + " ETAG_minus " - " ETAG_and " .and. " ETAG_or " .or. " ETAG_then " .then. " ETAG_pair " :: " ETAG_lt " < " ETAG_le " <= " ETAG_equal " = " ETAG_gt " > " ETAG_ge " >= " ETAG_apply " apply " ETAG_boolp " boolp ETAG_catch " catch ETAG_maptag1 " catching maptag ETAG_div " div " ETAG_head " head ETAG_intp " intp ETAG_boolg " is bool : " ETAG_intg " is int : " ETAG_mapg " is map : " ETAG_objg " is object : " ETAG_pairg " is pair : " ETAG_mapp " mapp ETAG_maptag " maptag ETAG_mod " mod " ETAG_norm " norm ETAG_objp " objectp ETAG_pairp " pairp ETAG_raise " raise ETAG_root " root ETAG_tail " tail ETAG_untag " untag ETAG_digitend %% ETAG_par ( " ) ETAG_uplus + " ETAG_dplus +" ETAG_uminus - " ETAG_dminus -" ETAG_not .not. " ETAG_Base Base ETAG_LET LET " BE " ETAG_ash ash ( " , " ) ETAG_bottom bottom ETAG_bt2bytes bt2byte* ( " ) ETAG_bt2vector bt2vector ( " ) ETAG_ceiling ceiling ( " , " ) ETAG_destruct destruct ( " ) ETAG_evenp evenp ( " ) ETAG_exception exception ETAG_false false ETAG_floor floor ( " , " ) ETAG_half half ( " ) ETAG_if if " then " else " ETAG_intlength integer-length ( " ) ETAG_logand logand ( " , " ) ETAG_logandc1 logandc1 ( " , " ) ETAG_logandc2 logandc2 ( " , " ) ETAG_logbitp logbitp ( " , " ) ETAG_logcount logcount ( " ) ETAG_logeqv logeqv ( " , " ) ETAG_logior logior ( " , " ) ETAG_lognand lognand ( " , " ) ETAG_lognor lognor ( " , " ) ETAG_lognot lognot ( " ) ETAG_logorc1 logorc1 ( " , " ) ETAG_logorc2 logorc2 ( " , " ) ETAG_logtest logtest ( " , " ) ETAG_logxor logxor ( " , " ) ETAG_map map ( " ) ETAG_prenorm norm " ETAG_notnot notnot " ETAG_object object ( " ) ETAG_print print ( " ) ETAG_round round ( " , " ) ETAG_spy spy ( " ) ETAG_timer timer ( " ) ETAG_trace trace ( " ) ETAG_truncate truncate ( " , " ) ETAG_vector vector ( " ) ETAG_vempty vector-empty ( " ) ETAG_vindex vector-index ( " , " ) ETAG_vlength vector-length ( " ) ETAG_vprefix vector-prefix ( " , " ) ETAG_vsubseq vector-subseq ( " , " , " ) ETAG_vsuffix vector-suffix ( " , " ) ETAG_v2bytes vector2byte* ( " ) ETAG_vt2bytes vt2byte* ( " ) ETAG_vt2v vt2vector ( " ) ETAG_yy YY ETAG_compile compile ( " ) */ /* Accessors */ #define ROOT(x) (((cell*)(x))->root) #define HEAD(x) (((cell*)(x))->head) #define TAIL(x) (((cell*)(x))->tail) /* Number of tags */ #define TAG_SIZE 256 /* Data tags */ #define TAG_FALSE 1 #define TAG_INT 2 #define TAG_VECT 3 #define TAG_PAIR 4 #define TAG_EX 5 #define TAG_MAP 6 #define TAG_OBJ 7 #define TAG_GARB 8 /* Term tags */ #define TTAG_APPLY 20 #define TTAG_LAMBDA 21 #define TTAG_VAR 22 #define TTAG_PAIR 23 #define TTAG_CONST 24 #define TTAG_CALL 25 #define TTAG_ECALL 26 /* Map tags */ #define MTAG_CLOSURE 30 #define MTAG_INDIR 31 #define MTAG_PAIR 32 #define MTAG_LAMBDA 33 #define MTAG_FIX 34 /* Class tags */ #define CTAG_MAP 40 #define CTAG_EMAP 41 #define CTAG_TRUE 42 #define CTAG_APPLY 43 #define CTAG_IF 44 /* Optimized function tags (ETAG for "eager tag" since most optimized functions are eager) */ #define ETAG_var 100 #define ETAG_ecall 101 #define ETAG_digit0 102 #define ETAG_digit1 103 #define ETAG_digit2 104 #define ETAG_digit3 105 #define ETAG_digit4 106 #define ETAG_digit5 107 #define ETAG_digit6 108 #define ETAG_digit7 109 #define ETAG_digit8 110 #define ETAG_digit9 111 #define ETAG_times 112 #define ETAG_plus 113 #define ETAG_minus 114 #define ETAG_and 115 #define ETAG_or 116 #define ETAG_then 117 #define ETAG_pair 118 #define ETAG_lt 119 #define ETAG_le 120 #define ETAG_equal 121 #define ETAG_gt 122 #define ETAG_ge 123 #define ETAG_apply 124 #define ETAG_boolp 125 #define ETAG_catch 126 #define ETAG_maptag1 127 #define ETAG_div 128 #define ETAG_head 129 #define ETAG_intp 130 #define ETAG_boolg 131 #define ETAG_intg 132 #define ETAG_mapg 133 #define ETAG_objg 134 #define ETAG_pairg 135 /* ETAG_valg 136*/ #define ETAG_mapp 137 #define ETAG_maptag 138 #define ETAG_mod 139 #define ETAG_norm 140 #define ETAG_objp 141 #define ETAG_pairp 142 #define ETAG_raise 143 #define ETAG_root 144 #define ETAG_tail 145 #define ETAG_untag 146 #define ETAG_digitend 147 #define ETAG_par 148 #define ETAG_uplus 149 #define ETAG_dplus 150 #define ETAG_uminus 151 #define ETAG_dminus 152 #define ETAG_not 153 #define ETAG_Base 154 #define ETAG_LET 155 #define ETAG_ash 156 #define ETAG_bottom 157 #define ETAG_bt2bytes 158 #define ETAG_bt2vector 159 #define ETAG_ceiling 160 #define ETAG_destruct 161 #define ETAG_evenp 162 #define ETAG_exception 163 #define ETAG_false 164 #define ETAG_floor 165 #define ETAG_half 166 #define ETAG_if 167 #define ETAG_intlength 168 #define ETAG_logand 169 #define ETAG_logandc1 170 #define ETAG_logandc2 171 #define ETAG_logbitp 172 #define ETAG_logcount 173 #define ETAG_logeqv 174 #define ETAG_logior 175 #define ETAG_lognand 176 #define ETAG_lognor 177 #define ETAG_lognot 178 #define ETAG_logorc1 179 #define ETAG_logorc2 180 #define ETAG_logtest 181 #define ETAG_logxor 182 #define ETAG_map 183 #define ETAG_prenorm 184 #define ETAG_notnot 185 #define ETAG_object 186 #define ETAG_print 187 #define ETAG_round 188 #define ETAG_spy 189 #define ETAG_timer 190 #define ETAG_trace 191 #define ETAG_truncate 192 #define ETAG_vector 193 #define ETAG_vempty 194 #define ETAG_vindex 195 #define ETAG_vlength 196 #define ETAG_vprefix 197 #define ETAG_vsubseq 198 #define ETAG_vsuffix 199 #define ETAG_v2bytes 200 #define ETAG_vt2bytes 201 #define ETAG_vt2v 202 #define ETAG_yy 203 #define ETAG_compile 204 /* True if x is *not* of given type */ #define GD_INT(x) ((ROOT(x)|1)!=TAG_VECT) #define GD_PAIR(x) (ROOT(x)!=TAG_PAIR) #define GD_EX(x) (ROOT(x)!=TAG_EX) #define GD_MAP(x) (ROOT(x)!=TAG_MAP) #define GD_OBJ(x) (ROOT(x)!=TAG_OBJ) /* True if x is *not* of given type */ #define NO_BOOL(x) (((x)!=T)&&(ROOT(x)!=TAG_FALSE)) #define NO_INT(x) (((x)==T)||GD_INT(x)) #define NO_PAIR(x) (((x)==T)||GD_PAIR(x)) #define NO_EX(x) (((x)==T)||GD_EX(x)) #define NO_MAP(x) (((x)==T)||GD_MAP(x)) #define NO_OBJ(x) (((x)==T)||GD_OBJ(x)) /* True if x is of given type */ #define IS_BOOL(x) (!NO_BOOL(x)) #define IS_INT(x) (!NO_INT (x)) #define IS_PAIR(x) (!NO_PAIR(x)) #define IS_EX(x) (!NO_EX (x)) #define IS_MAP(x) (!NO_MAP (x)) #define IS_OBJ(x) (!NO_OBJ (x)) /* NIL pointer, map truth, C truth and C falsehood */ #define NIL 0 #define T 0 #define TRUE 1 #define FALSE 0 #define ENDFILE 256 /* Conversion of negative x to -1 and other x to 0 */ #define SIGN(x) ((x)&signmask?M:Z) /* Operations on halfwords */ #define HALFHEAD(x) ((x)&halfmask) #define HALFTAIL(x) ((x)>>halfsize) #define HALFCONS(x,y) (((x)&halfmask)+((y)<=TAG_SIZE) return TRUE; if(tag2string[tag]==NIL) return TRUE; return FALSE;} char *safe_tag2string(pnt tag){ if(invalid_tag(tag)) return "TAG_UNKNOWN"; return tag2string[tag];} void spytag(pnt tag){ if(tag&signmask) printf("*"); printf("%s",safe_tag2string(tag&~signmask));} void spytag0(pnt tag){ spytag(tag); printf("\n");} void spytagroot1(pnt x){ if(x==T) printf("TAG_TRUE"); else spytag(ROOT(x));} void spytagroot0(pnt x){ spytagroot1(x); printf("\n");} void unexpected_tag(char *msg,pnt value){ printf("%s: unexpected tag: ",msg); spytagroot0(value); die("Goodbye");} void spyint0(pnt x){ printf("%u",HEAD(x)); for(x=TAIL(x);x;x=TAIL(x)) printf(" %u",HEAD(x));} void spyvect(pnt x){ printf("\""); for(;TAIL(x);x=TAIL(x)){ pnt i; pnt y=HEAD(x); for(i=0;i>8;}} for(x=HEAD(x);x>1;x=x>>8) printchar(x); printf("\"");} void spyint1(pnt x){ if((TAIL(x)==T)&&((HEAD(x)<10000)||((HEAD(x))>1+~10000))){ printf("%5d",(int)(HEAD(x))); return;} printf("#"); spyvect(x);} void spyname(pnt x,pnt arglist){ for(;TAIL(x);x=TAIL(x)){ pnt i; pnt y=HEAD(x); for(i=0;i>8;}} for(x=HEAD(x);x>1;x=x>>8) if((x&255)!='"'||NO_PAIR(arglist)) printchar(x); else {spy1(HEAD(arglist));arglist=TAIL(arglist);} if(arglist==T) return; printf(":"); spy1(arglist);} pnt root2name(pnt x){ pnt root,ref,idx,name; root=HEAD(x); if(NO_PAIR(root)) return TRUE; ref=HEAD(root); if(NO_INT(ref)) return TRUE; if(NO_PAIR(TAIL(root))) return TRUE; idx=HEAD(TAIL(root)); if(NO_INT(idx)) return TRUE; if(ref==Z){printf("(");spy1(idx);printf(")");return FALSE;} name=nameget(state,ref,idx); if(name==T) return TRUE; spyname(name,TAIL(x)); return FALSE;} void spy1(pnt x){ pnt tag; if(spycnt==0){printf("...");return;} spycnt--; if(x==T){printf("T");return;} tag=ROOT(x); if(tag&signmask) printf("*"); tag=tag&~signmask; switch(tag){ case TAG_FALSE: printf("F");return; case TAG_INT: spyint0(x);return; case TAG_VECT: spyvect(x);return; case TAG_PAIR: if(root2name(x)) prn2("P",HEAD(x),TAIL(x));return; case TAG_EX: prn1("X",HEAD(x));return; case TAG_MAP: printf("M(%s,",safe_tag2string(TAIL(x))); spy1(HEAD(x));printf(")");return; case TAG_OBJ: prn2("O",HEAD(HEAD(x)),TAIL(HEAD(x)));spy1(TAIL(x));return; case TAG_GARB: printf("G(%d)",((cell *)x)-heap);return; case TTAG_VAR: printf("TTAG_VAR(%d)",HEAD(x));return; case TTAG_LAMBDA: prn1("TTAG_LAMBDA",HEAD(x));return; case TTAG_CONST: prn1("TTAG_CONST",HEAD(x));return; case MTAG_INDIR: prn1("MTAG_INDIR",TAIL(x));return; case MTAG_CLOSURE:printf("CLOSURE");return; case ETAG_var: printf("ETAG_var(%d)",HEAD(x));return; case ETAG_ecall: prn2("ETAG_ecall",HEAD(x),TAIL(x));return;} if(invalid_tag(tag)) {printf("??");return;} prn2(tag2string[tag],HEAD(x),TAIL(x));} void spy2(pnt x,pnt y){ spycnt=x; spy1(y);} pnt spy0(pnt x){ spy2(100,x); printf("\n"); return x;} void spydie(pnt x,char *msg){ spy0(x); die(msg);} void backtrace(pnt x,pnt cnt){ pnt i; pnt y; pnt tag; if(cnt==0) return; printf("backtrace %3d: %10d\n",cnt,x); spy0(x); if(x==state){printf("Referenced from state\n");return;} if(x==global_x){printf("Referenced from head\n");return;} if(x==global_y){printf("Referenced from tail\n");return;} for(i=sp;i=0) return (pnt)i; return 1+~(pnt)(-i);} /* Convert C integer to integer */ pnt int2int(spnt i){ return icons(int2pnt(i),NIL);} /* Convert C integer to normalized integer */ pnt JN(spnt i){ if(i==0) return Z; if(i==-1) return M; return keep(int2int(i));} pnt K2(spnt i,spnt j){ return keep(intcons(int2pnt(i),JN(j)));} /*********************** * VECTOR CONSTRUCTORS * ***********************/ pnt consvec(pnt head,pnt tail){ pnt result=fresh(NIL,tail); ROOT(result)=TAG_VECT; HEAD(result)=head; TAIL(result)=tail; return result;} pnt int2vec(pnt x){ if(NO_INT(x)) return x; return consvec(HEAD(x),TAIL(x));} /* Destructive. Only for use in main */ pnt vec2int(pnt x){ if(NO_INT(x)) die("vec2int applied to non-int"); ROOT(x)=TAG_INT; return x;} pnt str2vec2(unsigned char *str,pnt len){ if(len==0) return 1; return (*str)|(str2vec2(str+1,len-1)<<8);} pnt str2vec1(unsigned char *str,pnt len){ if(len " */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(cmp1(x,y)>1) return T; else return F;} pnt le(pnt x,pnt y){/* " <= " */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(cmp1(x,y)<=1) return T; else return F;} pnt ge(pnt x,pnt y){/* " >= " */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(cmp1(x,y)>=1) return T; else return F;} pnt evenp(pnt x){/* evenp ( " ) */ if(NO_INT(x)) return X; if(HEAD(x)&1) return F; else return T;} pnt half1(pnt x){ pnt v=HEAD(x); pnt y=v>>1; pnt z=TAIL(x); if(!z){if(v&signmask) return intcons(y+signmask,M); else return intcons(y,Z);} if(HEAD(z)&1) y=y+signmask; return intcons(y,half1(z));} pnt half(pnt x){/* half ( " ) */ if(NO_INT(x)) return X; return half1(x);} pnt small(pnt x){ if(NO_INT(x)) return X; if(x==Z) return T; if(x==M) return T; return F;} pnt base(){/* Base */ return I[10];} pnt zero(){/* %% */ return Z;} pnt unaryPlus(pnt x){/* + " */ if(NO_INT(x)) return X; return x;} pnt plus1(pnt x,pnt y,pnt c){ pnt X=HEAD(x); pnt Y=HEAD(y); pnt u=HALFHEAD(X)+HALFHEAD(Y)+c; pnt v=HALFTAIL(X)+HALFTAIL(Y)+HALFTAIL(u); pnt w=HALFCONS(u,v); if(TAIL(x)||TAIL(y)) return intcons(w,plus1(inttail(x),inttail(y),HALFTAIL(v))); if(w&signmask){ if((X&signmask)||(Y&signmask)) return intcons(w,M); else return intcons(w,Z);} else{ if((!(X&signmask))||(!(Y&signmask))) return intcons(w,Z); else return intcons(w,M);}} pnt plus(pnt x,pnt y){/* " + " */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; return plus1(x,y,0);} pnt minus(pnt x,pnt y){/* " - " */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; push(x); return ret(1,plus1(x,lognot(y),1));} pnt unaryMinus(pnt x){/* - " */ return minus(Z,x);} pnt integerLength3(pnt x){ if(!x) return 0; return 1+integerLength3(x>>1);} pnt integerLength2(pnt x){ if(x&signmask) return integerLength3(~x); return integerLength3(x);} pnt integerCombine(pnt x,pnt y){ pnt u=HALFHEAD(y)*pntsize+x; pnt v=HALFTAIL(y)*pntsize+HALFTAIL(u); return intcons(HALFCONS(u,v),intcons(HALFTAIL(v),Z));} pnt integerLength1(pnt x,pnt y){ if(TAIL(x)) return integerLength1(TAIL(x),y+1); return integerCombine(integerLength2(HEAD(x)),y);} pnt integerLength(pnt x){/* integer-length ( " ) */ if(NO_INT(x)) return X; return integerLength1(x,0);} pnt logcount2(pnt x){ if(!x) return 0; return (x&1)+logcount2(x>>1);} pnt logcount1(pnt x,pnt y){ y=y+logcount2(HEAD(x)); if(y&signmask) die("logcount overflow"); if(TAIL(x)) return logcount1(TAIL(x),y); return intcons(y,Z);} pnt logcount(pnt x){/* logcount ( " ) */ if(NO_INT(x)) return X; if(ge(x,Z)==T) return logcount1(x,0); return logcount1(lognot(x),0);} /* compute 10*x+y */ pnt digit(pnt x,pnt y){ pnt x0=HEAD(x); pnt x1=HALFHEAD(x0)*10+y; pnt x2=HALFTAIL(x0)*10+HALFTAIL(x1); pnt x3=HALFCONS(x1,x2); pnt y1=HALFTAIL(x2); if(!TAIL(x)&&(y1==0)&&!(x3&signmask)) return intcons(x3,Z); if(!TAIL(x)&&(y1==9)&&(x3&signmask)) return intcons(x3,M); return intcons(x3,digit(inttail(x),y1));} pnt digit0(pnt x){if(NO_INT(x)) return X;return digit(x,0);} /* " %0 */ pnt digit1(pnt x){if(NO_INT(x)) return X;return digit(x,1);} /* " %1 */ pnt digit2(pnt x){if(NO_INT(x)) return X;return digit(x,2);} /* " %2 */ pnt digit3(pnt x){if(NO_INT(x)) return X;return digit(x,3);} /* " %3 */ pnt digit4(pnt x){if(NO_INT(x)) return X;return digit(x,4);} /* " %4 */ pnt digit5(pnt x){if(NO_INT(x)) return X;return digit(x,5);} /* " %5 */ pnt digit6(pnt x){if(NO_INT(x)) return X;return digit(x,6);} /* " %6 */ pnt digit7(pnt x){if(NO_INT(x)) return X;return digit(x,7);} /* " %7 */ pnt digit8(pnt x){if(NO_INT(x)) return X;return digit(x,8);} /* " %8 */ pnt digit9(pnt x){if(NO_INT(x)) return X;return digit(x,9);} /* " %9 */ pnt str2int1(char *str,pnt result){ if(*str==0) return result; if(*str=='-') return unaryMinus(str2int1(str+1,result)); if(*str<'0') return str2int1(str+1,result); if(*str>'9') return str2int1(str+1,result); return str2int1(str+1,digit(result,*str-'0'));} pnt str2int0(unsigned char *str){ pnt result=store_find((pnt)2,str); if(result!=T) return result; return keep3((pnt)2,str,str2int1(str,Z));} pnt str2int(char *str){ return str2int0((unsigned char *)str);} pnt alloc1(pnt x){ if(!x) return NIL; return icons(0,alloc1(TAIL(x)));} pnt alloc2(pnt x,pnt y){ if(!x) return alloc1(y); return icons(0,alloc2(TAIL(x),y));} pnt normalize(pnt x){ pnt u=HEAD(x); if(TAIL(x)) return intcons(u,normalize(TAIL(x))); if(u==0) return Z; if(u==~(pnt)0) return M; return x;} /* x: First factor y: Second factor z: Product x1: Pointer which traverses x y1: Pointer which traverses y z1: Pointer which traverses z synchronously with x z2: Pointer which traverses z synchronously with y a: Current word from x b: Current word from y c1: Carry 1 c2: Carry 2 d0: Product, low half d1: Product, high half */ pnt umul(pnt x,pnt y){ pnt z,x1,y1,z1,z2,a,b,c1,c2,d0,d1,d2; z=alloc2(x,y); z1=z; for(x1=x;x1;x1=TAIL(x1)){ c1=0; z2=z1; a=HEAD(x1); for(y1=y;y1;y1=TAIL(y1)){ b=HEAD(y1); c2=HEAD(z2); d0=HALFHEAD(a)*HALFHEAD(b)+HALFHEAD(c1)+HALFHEAD(c2); d1=HALFHEAD(a)*HALFTAIL(b)+HALFTAIL(d0)+HALFTAIL(c1); d2=HALFTAIL(a)*HALFHEAD(b)+HALFHEAD(d1)+HALFTAIL(c2); c1=HALFTAIL(a)*HALFTAIL(b)+HALFTAIL(d1)+HALFTAIL(d2); HEAD(z2)=HALFCONS(d0,d2); z2=TAIL(z2); } HEAD(z2)=c1; z1=TAIL(z1); } return normalize(z);} pnt times(pnt x,pnt y){/* " * " */ pnt tmp1; if(NO_INT(x)) return X; if(NO_INT(y)) return X; push(x); push(y); if(ge(x,Z)==T){ if(ge(y,Z)==T) return ret(2,umul(x,y)); push(unaryMinus(y)); return ret(3,unaryMinus(umul(x,stack[sp])));} push(unaryMinus(x)); if(ge(y,Z)==T) return ret(3,unaryMinus(umul(stack[sp],y))); push(unaryMinus(y)); return ret(4,umul(stack[sp],stack[sp+1]));} pnt logbitp1(pnt x,pnt y){ if(!y) die("logbitp internal error"); if(x>=pntsize) return logbitp1(x-pntsize,TAIL(y)); if((HEAD(y)>>x)&1) return T; return F;} pnt logbitp(pnt x,pnt y){/* logbitp ( " , " ) */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(lt(x,Z)==T) return X; if(le(integerLength(y),x)==T) return lt(y,Z); if(TAIL(x)) die("logbitp overflow"); return logbitp1(HEAD(x),y);} pnt asll(pnt x,pnt y){ if(y==0) return x; return intcons(0,asll(x,y-1));} pnt asrr(pnt x,pnt y){ if(y==0) return x; return asrr(inttail(x),y-1);} pnt asl1(pnt x,pnt y,pnt c){ pnt x1=HEAD(x); pnt x2=(x1<>(pntsize-y)); if(x==Z) return intcons(x2,Z); if(x==M) return intcons(x2,M); return intcons(x2,asl1(inttail(x),y,c2));} pnt asl(pnt x,pnt y){ if(y==0) return x; return asl1(x,y,0);} pnt asr(pnt x,pnt y){ if(y==0) return x; return inttail(asl1(x,pntsize-y,0));} pnt ash(pnt x,pnt y){/* ash ( " , " ) */ pnt z; if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(TAIL(y)) die("ash overflow"); z=HEAD(y); if(ge(y,Z)==T) return asll(asl(x,z%pntsize),z/pntsize); z=1+~z; return asrr(asr(x,z%pntsize),z/pntsize);} /* The division algorithms below leave room for HUGE improvements. */ /* Returns 2x */ pnt twice0(pnt x){ return asl1(x,1,0);} /* Returns 2x+1 */ pnt twice1(pnt x){ return asl1(x,1,1);} /* pairUnaryMinus(q::r)=(-q)::(-r) */ pnt pairUnaryMinus(pnt x){ pnt y=HEAD(x); pnt z=TAIL(x); push(z); y=unaryMinus(y); push(y); return ret(2,pair(y,unaryMinus(z)));} /* divAdjust(q::r,d)=(q+1)::(r-d) */ pnt divAdjust(pnt x,pnt d){ pnt q=HEAD(x); pnt r=TAIL(x); push(q); r=minus(r,d); push(r); return ret(2,pair(plus(q,I[1]),r));} /* Divide non-negative remainder with positive divisor. floor1(x,y) divides x by y and returns pair(quotient,remainder). The remainder satisfies 0 <= remainder < y. floor1 does not secure its first argument against GC. */ pnt floor1(pnt dividend,pnt divisor){ pnt result,quotient,remainder,remainder1; push(divisor); if(lt(dividend,divisor)==T) return ret(1,pair(Z,dividend)); result=floor1(dividend,twice0(divisor)); push(result); quotient=HEAD(result); remainder=TAIL(result); remainder1=minus(remainder,divisor); if(lt(remainder1,Z)==T) return ret(2,pair(twice0(quotient),remainder)); push(remainder1); return ret(3,pair(twice1(quotient),remainder1));} /* Version of floor which secures both arguments against GC */ pnt floor0(pnt dividend,pnt divisor){ push(dividend); return ret(1,floor1(dividend,divisor));} /* dividend>=0, divisor>0 */ pnt ceiling0(pnt dividend,pnt divisor){ pnt result; result=floor0(dividend,divisor); if(TAIL(result)==Z) return result; return divAdjust(result,divisor);} /* dividend>=0, divisor>0 */ pnt round0(pnt dividend,pnt divisor){ pnt result,result1; push(divisor); result=floor0(dividend,divisor); push(result); result1=cmp1(twice0(TAIL(result)),divisor); if(result1==0) return ret(2,result); if(result1==2) return ret(2,divAdjust(result,divisor)); if(evenp(HEAD(result))==T) return ret(2,result); return ret(2,divAdjust(result,divisor));} pnt floorx(pnt x,pnt y){/* floor ( " , " ) */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(le(y,Z)==T) return X; if(ge(x,Z)==T) return floor0(x,y); push(y); return ret(1,pairUnaryMinus(ceiling0(unaryMinus(x),y)));} pnt ceilingx(pnt x,pnt y){/* ceiling ( " , " ) */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(le(y,Z)==T) return X; if(ge(x,Z)==T) return ceiling0(x,y); push(y); return ret(1,pairUnaryMinus(floor0(unaryMinus(x),y)));} pnt truncatex(pnt x,pnt y){/* truncate ( " , " ) */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(le(y,Z)==T) return X; if(ge(x,Z)==T) return floor0(x,y); push(y); return ret(1,pairUnaryMinus(floor0(unaryMinus(x),y)));} pnt roundx(pnt x,pnt y){/* round ( " , " ) */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(le(y,Z)==T) return X; if(ge(x,Z)==T) return round0(x,y); push(y); return ret(1,pairUnaryMinus(round0(unaryMinus(x),y)));} pnt divx(pnt x,pnt y){/* " div " */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(le(y,Z)==T) return X; if(ge(x,Z)==T) return HEAD(floor0(x,y)); push(y); return ret(1,unaryMinus(HEAD(ceiling0(unaryMinus(x),y))));} pnt modx(pnt x,pnt y){/* " mod " */ if(NO_INT(x)) return X; if(NO_INT(y)) return X; if(le(y,Z)==T) return X; if(ge(x,Z)==T) return TAIL(floor0(x,y)); push(y); return ret(1,unaryMinus(TAIL(ceiling0(unaryMinus(x),y))));} pnt raise0(pnt x){/* " raise */ return cons(TAG_EX,x,NIL);} pnt object(pnt x){/* object ( " ) */ pnt tag,ref,idx,val,cmp; if(NO_PAIR(x)) return X; tag=HEAD(x); val=TAIL(x); if(NO_PAIR(tag)) return X; ref=HEAD(tag); idx=TAIL(tag); if(NO_INT(ref)) return X; if(NO_INT(idx)) return X; cmp=cmp1(ref,Z); if(cmp==0) return X; if(T==lt(idx,I[(cmp==1)?5:0])) return X; return cons(TAG_OBJ,tag,val);} pnt destruct(pnt x){/* destruct ( " ) */ if(NO_OBJ(x)) return X; return pair(HEAD(x),TAIL(x));} pnt vector2(pnt x){ if(x<256) return 1; return (x&0xFF)|(vector2(x>>8)<<8);} pnt vector1(pnt x){ pnt u=HEAD(x); pnt y=TAIL(x); if(y==NIL||y==Z) return consvec(vector2(u),NIL); return consvec(u,vector1(y));} pnt vector(pnt x){/* vector ( " ) */ pnt length; if(x==T) return X; switch(ROOT(x)){ case TAG_VECT: return x; case TAG_INT: if(le(x,Z)==T) return E; return vector1(x); default: return X;}} pnt vectorEmpty(pnt x){/* vector-empty ( " ) */ return le(x,I[255]);} pnt vectorLength2(pnt x){ if(x<256) return 0; return 1+vectorLength2(x>>8);} pnt vectorLength1(pnt x){ pnt y=TAIL(x); if((!y)||(y==Z)) return vectorLength2(HEAD(x)); return bytesize+vectorLength1(y);} pnt negative(pnt x){ if(ROOT(x)==TAG_VECT) return FALSE; for(;TAIL(x);x=TAIL(x)); return (HEAD(x)&signmask)!=0;} pnt vectorLength(pnt x){/* vector-length ( " ) */ if(NO_INT(x)) return X; if(negative(x)) return Z; return intcons(vectorLength1(x),Z);} pnt vectorIndex2(pnt x,pnt y){ if(y==0) return x&0xFF; return vectorIndex2(x>>8,y-1);} pnt vectorIndex1(pnt x,pnt y){ if(y=vectorLength1(x)) return X; return intcons(vectorIndex1(x,HEAD(y)),Z);} pnt vectorSuffix2(pnt x,pnt y,pnt z){ pnt u=HEAD(x); pnt v=TAIL(x); if(v) return consvec((u>>y)|(HEAD(v)<>y; if(v==0) return NIL; return consvec(v,NIL);} pnt vectorSuffix1(pnt x,pnt y){ if(y==0) return vector(x); if(y>8,y-1)<<8);} pnt vectorPrefix1(pnt x,pnt y){ pnt u=HEAD(x); if(y>y1)|(v<>y1)|(HEAD(v)<>8,y));} pnt vector2bytes2(pnt x,pnt y,pnt z){ if(!y) return z; return pair(I[x&0xFF],vector2bytes2(x>>8,y-1,z));} pnt vector2bytes1(pnt x,pnt y){ if(!TAIL(x)) return vector2bytes3(HEAD(x),y); return vector2bytes2(HEAD(x),bytesize,vector2bytes1(TAIL(x),y));} pnt vector2bytes(pnt x){/* vector2byte* ( " ) */ if(NO_INT(x)) return X; if(negative(x)) return T; return vector2bytes1(x,T);} pnt bt2bytes1(pnt x,pnt y){ if(x==T) return y; switch(ROOT(x)){ case TAG_FALSE: case TAG_MAP: case TAG_OBJ: return y; case TAG_INT: case TAG_VECT: if(TAIL(x)) return y; if(HEAD(x)>255) return y; return pair(x,y); case TAG_PAIR: push(x); return ret(1,bt2bytes1(HEAD(x),bt2bytes1(TAIL(x),y))); default: unexpected_tag("bt2bytes1",x);}} pnt bt2bytes(pnt x){/* bt2byte* ( " ) */ return bt2bytes1(x,T);} pnt vt2bytes1(pnt x,pnt y){ if(x==T) return y; switch(ROOT(x)){ case TAG_FALSE: case TAG_MAP: case TAG_OBJ: return y; case TAG_INT: case TAG_VECT: if(negative(x)) return y; return vector2bytes1(x,y); case TAG_PAIR: push(x); return ret(1,vt2bytes1(HEAD(x),vt2bytes1(TAIL(x),y))); default: unexpected_tag("bt2bytes1",x);}} pnt vt2bytes(pnt x){/* vt2byte* ( " ) */ return vt2bytes1(x,T);} pnt bytes2vector(pnt n,pnt x){ pnt u,y; if(x==T) return consvec(1,NIL); u=HEAD(HEAD(x)); if(n==bytesize) return consvec(u,bytes2vector(1,TAIL(x))); y=bytes2vector(n+1,TAIL(x)); HEAD(y)=(HEAD(y)<<8)|u; return y;} pnt bt2vector(pnt x){/* bt2vector ( " ) */ return bytes2vector(1,bt2bytes(x));} pnt vt2vector(pnt x){/* vt2vector ( " ) */ return bytes2vector(1,vt2bytes(x));} pnt spy(pnt x){/* spy ( " ) */ spyvar=x; return const_spy;} pnt trace(pnt x){/* trace ( " ) */ spy0(x); return const_trace;} pnt print(pnt x){/* print ( " ) */ spy0(x); return const_print;} pnt timer(pnt x){/* timer ( " ) */ return const_timer;} /********************* * GENERAL FUNCTIONS * *********************/ pnt term_apply(pnt fct,pnt arg){ return cons(TTAG_APPLY,fct,arg);} pnt term_lambda(pnt body){ return cons(TTAG_LAMBDA,body,NIL);} pnt term_lambdas(pnt arity,pnt body){ if(arity==0) return body; return term_lambda(term_lambdas(arity-1,body));} pnt term_call(pnt fct,pnt arg){ return cons(TTAG_CALL,fct,arg);} pnt term_ecall(pnt fct,pnt arg){ return cons(TTAG_ECALL,fct,arg);} pnt term_var(pnt index){ return cons2(TTAG_VAR,index,NIL);} pnt term_pair(pnt x,pnt y){ return cons(TTAG_PAIR,x,y);} pnt term_const(pnt x){ return cons(TTAG_CONST,x,NIL);} pnt closure(pnt term,pnt env){ return cons(MTAG_CLOSURE,term,env);} pnt overwrite(pnt closure,pnt rnf){ ROOT(closure)=MTAG_INDIR; TAIL(closure)=rnf; return rnf;} pnt map_pair(pnt x,pnt y){ return cons(MTAG_PAIR,x,y);} pnt map_lambda(pnt term,pnt env){ return cons(MTAG_LAMBDA,term,env);} pnt bit2map(pnt x){ if(x&1) return map_f; else return map_t;} pnt small2rnf(pnt card){ if(card==0) return T; return map_pair(bit2map(card),small2rnf(card>>1));} pnt card2rnf1(pnt card,pnt cnt,pnt result){ if(cnt==0) return result; return map_pair(bit2map(card),card2rnf1(card>>1,cnt-1,result));} pnt card2rnf(pnt card){ pnt i,result,tmp1; if(TAIL(card)==T) return small2rnf(HEAD(card)); tmp1=HEAD(card); return card2rnf1(tmp1,pntsize,card2rnf(TAIL(card)));} pnt map2rnf(pnt map){ if(map==T) return T; switch(ROOT(map)){ case MTAG_INDIR: return TAIL(map); case MTAG_CLOSURE: push(map); return ret(1,overwrite(map,term2rnf(HEAD(map),TAIL(map)))); case MTAG_PAIR: case MTAG_LAMBDA: case MTAG_FIX: case TAG_FALSE: case TAG_INT: case TAG_VECT: case TAG_PAIR: case TAG_EX: case TAG_MAP: case TAG_OBJ: return map; default: unexpected_tag("map2rnf",map);}} pnt fixpoint(pnt map){ pnt env=map_pair(T,map_pair(map,T)); pnt result=closure(term_fix,env); HEAD(env)=result; return map2rnf(result);} void spyenv(pnt env){for(;env;env=TAIL(env)) spy0(HEAD(env));} pnt terms2closures(pnt terms,pnt env){ pnt closure0; if(terms==NIL) return NIL; closure0=closure(HEAD(terms),env); push(closure0); return ret(1,map_pair(closure0,terms2closures(TAIL(terms),env)));} pnt terms2tagged(pnt terms,pnt env){ pnt tagged1,tagged2; if(terms==NIL) return NIL; tagged2=terms2tagged(TAIL(terms),env); if(IS_EX(tagged2)) return tagged2; push(tagged2); tagged1=untag1(term2rnf(HEAD(terms),env)); if(IS_EX(tagged1)) return ret(1,tagged1); return ret(1,pair(tagged1,tagged2));} pnt map_apply(pnt map,pnt arg){ pnt rnf; push(arg); push(rnf=map2rnf(map)); if(rnf==T) return ret(2,rnf); switch(ROOT(rnf)){ case MTAG_PAIR: if(map2rnf(arg)==T) return ret(2,map2rnf(HEAD(rnf))); return ret(2,map2rnf(TAIL(rnf))); case MTAG_LAMBDA: return ret(2,term2rnf(HEAD(rnf),map_pair(arg,TAIL(rnf)))); case MTAG_FIX: return ret(2,fixpoint(arg)); case TAG_FALSE: map2rnf(arg); /* ensure infinite looping when appropriate */ return ret(2,T); case TAG_INT: case TAG_VECT: if(T==map2rnf(arg)) return ret(2,maptag_int); if(negative(rnf)) return ret(2,map_pair(map_f,card2rnf(unaryMinus(rnf)))); return ret(2,map_pair(map_t,card2rnf(rnf))); case TAG_PAIR: if(T==map2rnf(arg)) return ret(2,maptag_pair); return ret(2,map_pair(HEAD(rnf),TAIL(rnf))); case TAG_EX: if(T==map2rnf(arg)) return ret(2,maptag_ex); return ret(2,HEAD(rnf)); case TAG_MAP: if(T==map2rnf(arg)) return ret(2,maptag_map); return ret(2,map2rnf(HEAD(rnf))); case TAG_OBJ: if(map2rnf(arg)!=T) return ret(2,TAIL(rnf)); return ret(2, MAP_PAIR(card2rnf(HEAD(HEAD(rnf))),card2rnf(TAIL(HEAD(rnf))))); default: unexpected_tag("map_apply",rnf);}} pnt term2rnf(pnt term,pnt env){ push(term); push(env); switch(ROOT(term)){ case TTAG_APPLY:{ pnt rnf; rnf=term2rnf(HEAD(term),env); if(rnf==T) return ret(2,T); push(rnf); switch(ROOT(rnf)){ case MTAG_PAIR: if(T==term2rnf(TAIL(term),env)) return ret(3,map2rnf(HEAD(rnf))); return ret(3,map2rnf(TAIL(rnf))); case MTAG_LAMBDA: return ret(3, term2rnf(HEAD(rnf),map_pair(closure(TAIL(term),env),TAIL(rnf)))); case MTAG_FIX: return ret(3,fixpoint(term2rnf(TAIL(term),env))); case TAG_FALSE: term2rnf(TAIL(term),env); /* ensure infinite looping when appropriate */ return ret(3,NIL); case TAG_INT: case TAG_VECT: if(T==term2rnf(TAIL(term),env)) return ret(3,maptag_int); if(negative(rnf)) return ret(3,map_pair(map_f,card2rnf(unaryMinus(rnf)))); return ret(3,map_pair(map_t,card2rnf(rnf))); case TAG_PAIR: if(T==term2rnf(TAIL(term),env)) return ret(3,maptag_pair); return ret(3,map_pair(HEAD(rnf),TAIL(rnf))); case TAG_EX: if(T==term2rnf(TAIL(term),env)) return ret(3,maptag_ex); return ret(3,HEAD(rnf)); case TAG_MAP: if(T==term2rnf(TAIL(term),env)) return ret(3,maptag_map); return ret(3,map2rnf(HEAD(rnf))); case TAG_OBJ: if(term2rnf(TAIL(term),env)) return ret(3,TAIL(rnf)); return ret(3, MAP_PAIR(card2rnf(HEAD(HEAD(rnf))),card2rnf(TAIL(HEAD(rnf))))); default: unexpected_tag("term2rnf/apply",rnf);}} case TTAG_LAMBDA: return ret(2,map_lambda(HEAD(term),env)); case TTAG_CALL:{ /* current version allows call of n-ary CLOSED terms */ return ret(2,term2rnf(HEAD(term),terms2closures(TAIL(term),env)));} case TTAG_ECALL:{ pnt args; /* current version allows call of n-ary CLOSED terms */ args=terms2tagged(TAIL(term),env); if(IS_EX(args)) return ret(2,args); return ret(2,eval(HEAD(term),args));} case TTAG_VAR:{ pnt i; pnt n=HEAD(term); for(i=0;i0;R0--) env=TAIL(env); return HEAD(env); case ETAG_ecall : push(T); for(u=TAIL(term);u!=T;u=TAIL(u)){ v=eval(HEAD(u),env); if(IS_EX(v)) return ret(1,v); TOP=cons(TAG_PAIR,v,TOP);} return ret(1,eval(HEAD(term),TOP)); case ETAG_digit0 : EVAL1(digit0 ) case ETAG_digit1 : EVAL1(digit1 ) case ETAG_digit2 : EVAL1(digit2 ) case ETAG_digit3 : EVAL1(digit3 ) case ETAG_digit4 : EVAL1(digit4 ) case ETAG_digit5 : EVAL1(digit5 ) case ETAG_digit6 : EVAL1(digit6 ) case ETAG_digit7 : EVAL1(digit7 ) case ETAG_digit8 : EVAL1(digit8 ) case ETAG_digit9 : EVAL1(digit9 ) case ETAG_times : EVAL2(times ) case ETAG_plus : EVAL2(plus ) case ETAG_minus : EVAL2(minus ) case ETAG_and : R0=eval(HEAD(term),env); if(R0!=T) return R0; return eval(TAIL(term),env); case ETAG_or : R0=eval(HEAD(term),env); if(R0==T) return T; if(IS_EX(R0)) return R0; return eval(TAIL(term),env); case ETAG_then : EVAL2(then ) case ETAG_pair : EVAL2(pair ) case ETAG_lt : EVAL2(lt ) case ETAG_le : EVAL2(le ) case ETAG_equal : EVAL2(eq ) case ETAG_gt : EVAL2(gt ) case ETAG_ge : EVAL2(ge ) case ETAG_apply : EVAL2(apply ) case ETAG_boolp : EVAL1(boolp ) case ETAG_catch : R0=eval(TAIL(term),env); if(IS_EX(R0)) return pair(T,HEAD(R0)); return pair(F,R0); case ETAG_maptag1 : return mapcons(eval(TAIL(term),env)); case ETAG_div : EVAL2(divx ) case ETAG_head : EVAL1(head ) case ETAG_intp : EVAL1(intp ) case ETAG_boolg : EVAL2(boolg ) case ETAG_intg : EVAL2(intg ) case ETAG_mapg : EVAL2(mapg ) case ETAG_objg : EVAL2(objg ) case ETAG_pairg : EVAL2(pairg ) case ETAG_mapp : EVAL1(mapp ) case ETAG_maptag : R0=eval(TAIL(term),env); if(IS_EX(R0)) return R0; return mapcons(R0); case ETAG_mod : EVAL2(modx ) case ETAG_norm : EVAL1(norm ) case ETAG_objp : EVAL1(objp ) case ETAG_pairp : EVAL1(pairp ) case ETAG_raise : EVAL1(raise0 ) case ETAG_root : EVAL1(root ) case ETAG_tail : EVAL1(tail ) case ETAG_untag : EVAL1(untag ) case ETAG_digitend : EVAL0(zero ) case ETAG_par : EVAL1(norm ) case ETAG_uplus : EVAL1(unaryPlus ) case ETAG_dplus : EVAL1(unaryPlus ) case ETAG_uminus : EVAL1(unaryMinus ) case ETAG_dminus : EVAL1(unaryMinus ) case ETAG_not : EVAL1(not ) case ETAG_Base : EVAL0(base ) case ETAG_LET : R0=eval(HEAD(term),env); if(IS_EX(R0)) return R0; R0=pair(R0,env); push(R0); return ret(1,eval(TAIL(term),R0)); case ETAG_ash : EVAL2(ash ) case ETAG_bottom : EVAL0(bottom ) case ETAG_bt2bytes : EVAL1(bt2bytes ) case ETAG_bt2vector: EVAL1(bt2vector ) case ETAG_ceiling : EVAL2(ceilingx ) case ETAG_destruct : EVAL1(destruct ) case ETAG_evenp : EVAL1(evenp ) case ETAG_exception: EVAL0(exception ) case ETAG_false : EVAL0(false ) case ETAG_floor : EVAL2(floorx ) case ETAG_half : EVAL1(half ) case ETAG_if : R0=eval(HEAD(term),env); if(R0==T) return eval(HEAD(TAIL(term)),env); if(IS_EX(R0)) return R0; return eval(TAIL(TAIL(term)),env); case ETAG_intlength: EVAL1(integerLength) case ETAG_logand : EVAL2(logand ) case ETAG_logandc1 : EVAL2(logandc1 ) case ETAG_logandc2 : EVAL2(logandc2 ) case ETAG_logbitp : EVAL2(logbitp ) case ETAG_logcount : EVAL1(logcount ) case ETAG_logeqv : EVAL2(logeqv ) case ETAG_logior : EVAL2(logior ) case ETAG_lognand : EVAL2(lognand ) case ETAG_lognor : EVAL2(lognor ) case ETAG_lognot : EVAL1(lognot ) case ETAG_logorc1 : EVAL2(logorc1 ) case ETAG_logorc2 : EVAL2(logorc2 ) case ETAG_logtest : EVAL2(logtest ) case ETAG_logxor : EVAL2(logxor ) case ETAG_map : return mapcons(TAIL(term)); case ETAG_prenorm : EVAL1(norm ) case ETAG_notnot : EVAL1(notnot ) case ETAG_object : EVAL1(object ) case ETAG_print : EVAL1(print ) case ETAG_round : EVAL2(roundx ) case ETAG_spy : EVAL1(spy ) case ETAG_timer : EVAL1(timer ) case ETAG_trace : EVAL1(trace ) case ETAG_truncate : EVAL2(truncatex ) case ETAG_vector : EVAL1(vector ) case ETAG_vempty : EVAL1(vectorEmpty ) case ETAG_vindex : EVAL2(vectorIndex ) case ETAG_vlength : EVAL1(vectorLength ) case ETAG_vprefix : EVAL2(vectorPrefix ) case ETAG_vsubseq : EVAL3(vectorSubseq ) case ETAG_vsuffix : EVAL2(vectorSuffix ) case ETAG_v2bytes : EVAL1(vector2bytes ) case ETAG_vt2bytes : EVAL1(vt2bytes ) case ETAG_vt2v : EVAL1(vt2vector ) case ETAG_compile : EVAL1(compile ) default: unexpected_tag("eval",term);}} /******************* * Array functions * *******************/ void printdom(pnt a){ pnt head; if(a==T) return; if(GD_PAIR(a)) die("Unexpected type in array"); head=HEAD(a); if(!NO_INT(head)){ spy0(head); return;} printdom(head); printdom(TAIL(a));} pnt aget(pnt a,pnt i){ pnt head,i1,i2,bit; if(NO_INT(i)) return X; i2=i; i1=HEAD(i2); bit=0; for(;;){ if(a==T) return T; if(GD_PAIR(a)) return X; head=HEAD(a); if(IS_INT(head)){if(eq0(head,i)) return TAIL(a); else return T;} if((i1>>bit)&1) a=TAIL(a); else a=head; bit++; if(bit=pntsize) return getbit(x-pntsize,inttail(y)); return (HEAD(y)>>x)&1;} pnt aput2(pnt i1,pnt a,pnt i2,pnt v2,pnt b){ if(getbit(b,i1)==0){ if(getbit(b,i2)==0) return pair(aput2(i1,a,i2,v2,b+1),T); return pair(a,pair(i2,v2));} else{ if(getbit(b,i2)==1) return pair(T,aput2(i1,a,i2,v2,b+1)); return pair(pair(i2,v2),a);}} pnt aput1(pnt a,pnt i,pnt v,pnt b){ pnt head; pnt tail; if(a==T) return semipair2(i,v); if(GD_PAIR(a)) return a; head=HEAD(a); tail=TAIL(a); if(IS_INT(head)){ if(eq0(head,i)) return semipair2(i,v); if(v==T) return a; if(tail==T) return pair(i,v); return aput2(head,a,i,v,b);} if(getbit(b,i)==0) return semipair1(aput1(head,i,v,b+1),tail); return semipair1(head,aput1(tail,i,v,b+1));} pnt aput0(pnt a,pnt i,pnt v){ if(NO_INT(i)) return a; push(a); push(i); push(v); return ret(3,aput1(a,i,v,0));} pnt mput1(pnt array,pnt value,pnt index1){ return aput0(array,index1,value);} pnt mput2(pnt array,pnt value,pnt index1,pnt index2){ pnt subarray=aget(array,index1); push(array); push(index1); subarray=ret(2,mput1(subarray,value,index2)); return mput1(array,subarray,index1);} pnt mput3(pnt array,pnt value,pnt index1,pnt index2,pnt index3){ pnt subarray=aget(array,index1); push(array); push(index1); subarray=ret(2,mput2(subarray,value,index2,index3)); return mput1(array,subarray,index1);} pnt mput4(pnt array,pnt value,pnt index1,pnt index2,pnt index3,pnt index4){ pnt subarray=aget(array,index1); push(array); push(index1); subarray=ret(2,mput3(subarray,value,index2,index3,index4)); return mput1(array,subarray,index1);} /************* * Scripting * *************/ /* In scripts, blank lines and lines starting with a hash mark are ignored. LF (10) as well as CR (13) are considered as line terminators. A CRLF is considered as two linebreaks, but nobody will notice since blank lines are ignored. Sample scripts: #!/home/kgr/code/red/red/red.exe script codex 017451CF6643931035C71796AC493D382EC8357EE9A390D5D6DBCDAA0806 017451CF6643931035C71796AC493D382EC8357EE9A390D5D6DBCDAA0806 0 0 execute /home/kgr/code/red/lisp/cache /home/kgr/code/red/lisp/cache1 #!/home/kgr/code/red/red/red.exe script assoc 017451CF6643931035C71796AC493D382EC8357EE9A390D5D6DBCDAA0806 017451CF6643931035C71796AC493D382EC8357EE9A390D5D6DBCDAA0806 0 0 executables hello /home/kgr/code/red/lisp/cache /home/kgr/code/red/lisp/cache1 #!/home/kgr/code/red/red/red.exe script execute 017451CF6643931035C71796AC493D382EC8357EE9A390D5D6DBCDAA0806 /home/kgr/code/red/lisp/cache /home/kgr/code/red/lisp/cache1 #!/home/kgr/code/red/red/red.exe script executables 017451CF6643931035C71796AC493D382EC8357EE9A390D5D6DBCDAA0806 hello /home/kgr/code/red/lisp/cache /home/kgr/code/red/lisp/cache1 */ /* Return next input byte or ENDFILE (256) */ /* buf[] is also used by putch defined later */ #define BUFSIZE 1000000 unsigned char buf[BUFSIZE]; int bufpnt=0; int bufcnt=0; pnt getch(int fd){ if(bufpnt=PATHSIZE) die("Line too long"); c=getch(fd); line[i]=0; if(c==ENDFILE) return i!=0; if((c!=CR)&&(c!=LF)) line[i++]=c; else if((i>0)&&(line[0]!='#')) return TRUE; else i=0;}} /* Read one pnt, die on ENDFILE, die on overflow */ pnt readpnt(int fd){ pnt result; pnt byte=getch(fd); if(byte==ENDFILE) die("Unexpected end of file"); if(byte<128) return byte; result=readpnt(fd); if(result&septetmask) die("Pnt overflow"); return result*128+byte-128;} /************* * Read rack * *************/ /* Read one rack file and convert it into a structure with sharing. The reference is given as a file descriptor. The input file is treated as a sequence of bytes. The output structure is composed of the constant NIL, cardinals, and conses. In the input file, most cardinals are expressed base 128. Each such cardinal is represented as a sequence of 'middle septets' followed by an 'end septet'. Middle septets are represented by bytes in the range 128..255. End septets are represented by bytes in the range 0..127. Cardinals are expressed in little endian. As an example, "129 130 003" represents 1+128*2+16384*3. An input file represents a sequence of values, the last of which is the rack to be constructed. Each value in the sequence has an "index". The index of the first value is RACK_START, the index of the next is RACK_START+1, and so on. The constant NIL is represented by the cardinal RACK_NIL in base 128. A cardinal x is represented by the cardinal RACK_INT in base 128 followed by the cardinal x in base 128. A cons of two values y and z is represented by the index of y followed by the index of z. The indices of y and z are smaller than the index of the cons, so when scanning a rack file from start to end, the arguments of a cons will be constructed before the cons is constructed. A vector x is represented by the cardinal RACK_ARRAY in base 128 followed by the number of bytes in x expressed in base 128 followed by the bytes of x. Since a vector ultimately represents a cardinal, this is just a slightly more compact and less CPU consuming way of representing cardinals. */ pnt readrack1(int fd){ pnt sp1=sp; pnt sp2=sp+1; pnt card0; pnt card1; pnt index; pnt vector; pnt position; pnt *location; pnt result; push(T); /* stack[sp1-RACK_NIL] represents T */ push(T); /* stack[sp1-RACK_ARRAY] is unused */ for(;;){ index=sp2-sp; card0=readpnt(fd); if(card0==RACK_INT){ vector=icons(0,0); push(vector); location=stack+sp; position=0; do{ card1=getch(fd); HEAD(vector)|=((card1&127)<=pntsize){ position-=pntsize; TAIL(vector)=icons((card1&127)>>(7-position),0); location=&TAIL(vector); vector=TAIL(vector);}} while(card1>127); if(HEAD(vector)<256) *location=I[HEAD(vector)];} else if(card0==RACK_ARRAY){ vector=consvec(0,0); push(vector); for(card1=readpnt(fd);card1>=bytesize;card1-=bytesize){ for(position=0;position=index) die("Pointer too large"); if(card1==RACK_INT) die("Invalid tail"); if(card1==RACK_ARRAY) die("Invalid tail"); push(pair(stack[sp1-card0],stack[sp1-card1]));} else if(card0==index) break; else die("Pointer too large");} if(getch(fd)!=ENDFILE) die("ENDFILE expected"); result=stack[sp]; sp=sp1; return result;} /* Read one rack file and convert it into a structure with sharing. The reference is given as a mixed endian hexadecimal string. The readrack() function scans the path for a rack file with the given name and then invokes readrack1 on the file found. */ pnt make_path(char *result,pnt size,char *p1,char *p2,char *p3,char *p4){ char *match=strchr(p1,':'); pnt l1=match?(match-p1):strlen(p1); pnt l2=strlen(p2); pnt l3=strlen(p3); pnt l4=strlen(p4); if(l1+l2+l3+l4>=size) die("Path too long"); memcpy(result,p1,l1); memcpy(result+l1,p2,l2); memcpy(result+l1+l2,p3,l3); memcpy(result+l1+l2+l3,p4,l4); *(result+l1+l2+l3+l4)=0; return l1;} pnt readrack(char *hexref){ int fd; pnt result; char *path=getenv("LGW_PATH"); pnt length; unsigned char filename[PATHSIZE]; if(path==0) die("LGW_PATH not set"); for(;;){ length= make_path(filename,sizeof(filename),path,"/cache/",hexref,"/page.lgr"); path+=(length+1); if(length==0) continue; bufpnt=0; bufcnt=0; fd=open(filename,O_RDONLY); if(fd>=0){ TRUSTGC; result=readrack1(fd); UNTRUSTGC; return result;} if(errno!=ENOENT) pdie("open()"); if(*(path-1)==':') continue; printf("%s not found\n",hexref); die("Goodbye");}} /************************ * Reference conversion * ************************/ /* Functions for converting a reference to a mixed endian hexadecimal string and vice versa */ unsigned char pnt2hex(pnt p){ switch(p&15){ case 0x00:return '0'; case 0x01:return '1'; case 0x02:return '2'; case 0x03:return '3'; case 0x04:return '4'; case 0x05:return '5'; case 0x06:return '6'; case 0x07:return '7'; case 0x08:return '8'; case 0x09:return '9'; case 0x0A:return 'A'; case 0x0B:return 'B'; case 0x0C:return 'C'; case 0x0D:return 'D'; case 0x0E:return 'E'; case 0x0F:return 'F';}} pnt hex2pnt(unsigned char p){ switch(p){ case '0': return 0x00; case '1': return 0x01; case '2': return 0x02; case '3': return 0x03; case '4': return 0x04; case '5': return 0x05; case '6': return 0x06; case '7': return 0x07; case '8': return 0x08; case '9': return 0x09; case 'A': return 0x0A; case 'B': return 0x0B; case 'C': return 0x0C; case 'D': return 0x0D; case 'E': return 0x0E; case 'F': return 0x0F; default: die("Unexpected character in hex constant");}} /* Convert a vector to a mixed endian hexadecimal string. Store result in the "refname" global variable */ unsigned char bufrefname[PATHSIZE]; void ref2string(pnt ref){ pnt index=0; pnt i; pnt head,tail; if(NO_INT(ref)) die("ref2string called with non-integer\n"); for(;;){ head=HEAD(ref); tail=TAIL(ref); for(i=0;i=PATHSIZE) die("ref2string overflow"); if((head<256)&&(tail==NIL)){bufrefname[index]=0;return;} bufrefname[index++]=pnt2hex(head>>4); bufrefname[index++]=pnt2hex(head); head>>=8;} ref=tail;}} /* Convert a mixed endian hexadecimal string to a vector */ pnt string2ref2(unsigned char *str,pnt len){ if(len==0) return 1; return (hex2pnt(*str)<<4)|hex2pnt(*(str+1))|(string2ref2(str+2,len-1)<<8);} pnt string2ref1(unsigned char *str,pnt len){ if(len \""); init_name(ETAG_ge ,T,"\" >= \""); init_name(ETAG_apply ,T,"\" apply \""); init_name(ETAG_boolp ,T,"\" boolp"); init_name(ETAG_catch ,F,"\" catch"); init_name(ETAG_maptag1 ,F,"\" catching maptag"); init_name(ETAG_div ,T,"\" div \""); init_name(ETAG_head ,T,"\" head"); init_name(ETAG_intp ,T,"\" intp"); init_name(ETAG_boolg ,T,"\" is bool : \""); init_name(ETAG_intg ,T,"\" is int : \""); init_name(ETAG_mapg ,T,"\" is map : \""); init_name(ETAG_objg ,T,"\" is object : \""); init_name(ETAG_pairg ,T,"\" is pair : \""); init_name(ETAG_mapp ,T,"\" mapp"); init_name(ETAG_maptag ,F,"\" maptag"); init_name(ETAG_mod ,T,"\" mod \""); init_name(ETAG_norm ,T,"\" norm"); init_name(ETAG_objp ,T,"\" objectp"); init_name(ETAG_pairp ,T,"\" pairp"); init_name(ETAG_raise ,T,"\" raise"); init_name(ETAG_root ,T,"\" root"); init_name(ETAG_tail ,T,"\" tail"); init_name(ETAG_untag ,T,"\" untag"); init_name(ETAG_digitend ,T,"%%"); init_name(ETAG_par ,F,"( \" )"); init_name(ETAG_uplus ,T,"+ \""); init_name(ETAG_dplus ,T,"+\""); init_name(ETAG_uminus ,T,"- \""); init_name(ETAG_dminus ,T,"-\""); init_name(ETAG_not ,T,".not. \""); init_name(ETAG_Base ,T,"Base"); init_name(ETAG_LET ,F,"LET \" BE \""); init_name(ETAG_ash ,T,"ash ( \" , \" )"); init_name(ETAG_bottom ,T,"bottom"); init_name(ETAG_bt2bytes ,T,"bt2byte* ( \" )"); init_name(ETAG_bt2vector,T,"bt2vector ( \" )"); init_name(ETAG_ceiling ,T,"ceiling ( \" , \" )"); init_name(ETAG_destruct ,T,"destruct ( \" )"); init_name(ETAG_evenp ,T,"evenp ( \" )"); init_name(ETAG_exception,T,"exception"); init_name(ETAG_false ,T,"false"); init_name(ETAG_floor ,T,"floor ( \" , \" )"); init_name(ETAG_half ,T,"half ( \" )"); init_name(ETAG_if ,F,"if \" then \" else \""); init_name(ETAG_intlength,T,"integer-length ( \" )"); init_name(ETAG_logand ,T,"logand ( \" , \" )"); init_name(ETAG_logandc1 ,T,"logandc1 ( \" , \" )"); init_name(ETAG_logandc2 ,T,"logandc2 ( \" , \" )"); init_name(ETAG_logbitp ,T,"logbitp ( \" , \" )"); init_name(ETAG_logcount ,T,"logcount ( \" )"); init_name(ETAG_logeqv ,T,"logeqv ( \" , \" )"); init_name(ETAG_logior ,T,"logior ( \" , \" )"); init_name(ETAG_lognand ,T,"lognand ( \" , \" )"); init_name(ETAG_lognor ,T,"lognor ( \" , \" )"); init_name(ETAG_lognot ,T,"lognot ( \" )"); init_name(ETAG_logorc1 ,T,"logorc1 ( \" , \" )"); init_name(ETAG_logorc2 ,T,"logorc2 ( \" , \" )"); init_name(ETAG_logtest ,T,"logtest ( \" , \" )"); init_name(ETAG_logxor ,T,"logxor ( \" , \" )"); init_name(ETAG_map ,F,"map ( \" )"); init_name(ETAG_prenorm ,T,"norm \""); init_name(ETAG_notnot ,T,"notnot \""); init_name(ETAG_object ,T,"object ( \" )"); init_name(ETAG_print ,T,"print ( \" )"); init_name(ETAG_round ,T,"round ( \" , \" )"); init_name(ETAG_spy ,T,"spy ( \" )"); init_name(ETAG_timer ,T,"timer ( \" )"); init_name(ETAG_trace ,T,"trace ( \" )"); init_name(ETAG_truncate ,T,"truncate ( \" , \" )"); init_name(ETAG_vector ,T,"vector ( \" )"); init_name(ETAG_vempty ,T,"vector-empty ( \" )"); init_name(ETAG_vindex ,T,"vector-index ( \" , \" )"); init_name(ETAG_vlength ,T,"vector-length ( \" )"); init_name(ETAG_vprefix ,T,"vector-prefix ( \" , \" )"); init_name(ETAG_vsubseq ,T,"vector-subseq ( \" , \" , \" )"); init_name(ETAG_vsuffix ,T,"vector-suffix ( \" , \" )"); init_name(ETAG_v2bytes ,T,"vector2byte* ( \" )"); init_name(ETAG_vt2bytes ,T,"vt2byte* ( \" )"); init_name(ETAG_vt2v ,T,"vt2vector ( \" )"); init_name(ETAG_yy ,F,"YY"); init_name(ETAG_compile ,T,"compile ( \" )"); } /****************** * Term accessors * ******************/ pnt term2ref(pnt term){ return head(head(term));} pnt term2idx(pnt term){ return head(tail(head(term)));} pnt term2arg1(pnt term){ return head(tail(term));} pnt term2arg2(pnt term){ return head(tail(tail(term)));} pnt term2arg3(pnt term){ return head(tail(tail(tail(term))));} pnt def2lhs(pnt def){ return term2arg2(def);} pnt def2arg(pnt def){ return tail(def2lhs(def));} pnt def2rhs(pnt def){ return term2arg3(def);} /******************* * Translate names * *******************/ pnt name2sym4(pnt cache,pnt idx,pnt ref,pnt name){ pnt cache1; cache1=mget2(cache,Z,const_name); if(cache1==T) return T; cache1=head(tail(tail(tail(cache1)))); cache1=head(tail(head(cache1))); if(eq0(cache1,name)) return pair(ref,idx); return T;} pnt name2sym3(pnt cache,pnt ref,pnt name){ pnt result; if(cache==T) return T; if(IS_INT(head(cache))) return name2sym4(TAIL(cache),HEAD(cache),ref,name); result=name2sym3(HEAD(cache),ref,name); if(result!=T) return result; return name2sym3(TAIL(cache),ref,name);} pnt name2sym2(pnt cache,pnt ref,pnt name){ return name2sym3(mget3(cache,ref,const_codex,ref),ref,name);} pnt name2sym1(pnt cache,pnt name){ pnt result; if(cache==T) return T; if(IS_INT(head(cache))) return name2sym2(TAIL(cache),HEAD(cache),name); result=name2sym1(HEAD(cache),name); if(result!=T) return result; return name2sym1(tail(cache),name);} pnt name2sym(char name1[]){ pnt name; name=str2vec1(name1,strlen(name1)); return name2sym1(state,name);} pnt name2ref(char name1[]){ pnt sym=name2sym(name1); if(sym==T) {printf("%s\n",name1);die("No code found");} return head(sym);} pnt name2idx(char name1[]){ pnt sym=name2sym(name1); if(sym==T) {printf("%s\n",name1);die("No code found");} return tail(sym);} pnt name2code(char name1[]){ pnt sym; pnt ref; pnt idx; sym=name2sym(name1); if(sym==T) {printf("%s\n",name1);die("No code found");} ref=HEAD(sym); idx=TAIL(sym); return mget4(state,ref,ref,const_code,idx);} pnt name2code1(pnt code,char name1[]){ return mget1(code,name2idx(name1));} /************************ * Compilation, stage 1 * ************************/ /* During stage 1, an initial value for the code array is constructed. The code array is constructed in the top element of the stack. The code array has one entry per construct with a non-empty value aspect. The code array is indexed by the index of each construct. For proclaimed constructs (lambda, quote, true, apply, and if), code[idx] is set to the value code[idx] is eventually going to have. (0 for lambda, 1 for quote, and various tagged maps for the other three). For defined and introduced constructs, code[idx] is set to a tagged map whose 'hidden tag' is set to CTAG_EMAP because any definition is deemed eager until the converse has been proved. During later stages, this hidden tag is updated to reflect the outcome of various static analysis. The hidden tag has no influence on the semantics of the entries. For defined and introduced constructs, the map part of code[idx] is set to as many lambdas as the arity of the construct indicates followed by a pair construct followed by the definition of the construct. During stage 5 and 6, the pair is overwritten with the compiled version of the definition. This allows to implement mutual recursion with circular call structures. */ pnt term2fct(pnt arity,pnt term){ if(arity==0) return closure(term,NIL); return map_lambda(term_lambdas(arity-1,term),NIL);} void initcode(pnt codex){ pnt hd; pnt tl; pnt def; pnt arg; pnt arity; if(codex==T) return; if(GD_PAIR(codex)) die("Unexpected type in codex"); hd=HEAD(codex); tl=TAIL(codex); if(NO_INT(hd)){initcode(hd);initcode(tl);return;} def=mget2(tl,Z,const_value); if(def==T) return; if(!eq0(head(head(def)),Z)){ arity=0; for(arg=tail(head(tail(tail(def))));arg!=T;arg=TAIL(arg)) arity++; TOP=aput0(TOP,hd,mapcons2(CTAG_EMAP,term2fct(arity,pair(def,T)))); return;} def=head(tail(head(def))); if(eq0(def,const_lambda)){TOP=aput0(TOP,hd,fct_lambda); return;} if(eq0(def,const_apply)){TOP=aput0(TOP,hd,fct_apply); return;} if(eq0(def,const_if)){TOP=aput0(TOP,hd,fct_if); return;} if(eq0(def,const_true)){TOP=aput0(TOP,hd,fct_true); return;} if(eq0(def,const_quote)){TOP=aput0(TOP,hd,fct_quote); return;} spy0(int2vec(def)); die("Unknown value proclamations");} /***************************************** * Compilation, stage 2, record patterns * *****************************************/ /* During the stage 2, the official definitions of optimized functions are collected. This is done one basis of the cache of a reference page. The constructs on the reference page are recognized using their Logiweb names. Optimized function i is supposed to have Logiweb name tag2name[i]. Once a construct with name tag2name[i] is located in the cache of the reference page, the value definition of that construct is taken to be the official definition of optimized function i. Stage 2 of the compilation is only performed when translating the reference page. A complete compilation consists of compilation of the reference page, including stage 2, followed by compilation of the source page, excluding stage 2. Note that the source page can be identical to the reference page in which case translation of the source page will be trivial since it is already compiled. Also note that the source page may transitively reference to reference page in which case the reference page is only compiled once. One could stop compilation of the reference page after stage 2 if it is not transitively referenced by the source page, but the reference page is translated to completion in all cases for simplicity. The algorithm uses the code array produced in stage 1. One could have based the algorithm on the codex instead of the code, leading to a cleaner but more complex algorithm. The algorithm actually used is "unclean" in the sense that it depends on the particular output from stage 1 even though it could have depended only on the completely standardized format of the cache and codex. */ pnt nameget(pnt caches,pnt ref,pnt idx){ pnt def=defget(caches,ref,idx,const_name); if(def==T) return T; return term2idx(def2rhs(def));} void nameprint1(pnt caches,pnt term){ pnt ref=term2ref(term); pnt idx=term2idx(term); if(term==T) printf(" T"); else if(ref==Z){printf("string ");spy2(1,idx);} else {spy2(1,term2idx(term));spy2(1,nameget(caches,ref,idx));}} void nameprint0(pnt caches,pnt term){ nameprint1(caches,term); printf("\n");} /* Skip the mtag_closure, mtag_lambda, and ttag_lambda constructs at the root of code entries and return the pair which is eventually going to be overwritten with the compiled version of the code entry. The given term entry is supposed to be a mapcons so skiparg cannot be used on lambdas and quotes. */ pnt code2pair(pnt term){ for(term=HEAD(term);ROOT(term)!=TAG_PAIR;term=HEAD(term)); return term;} /* Same as above, but return the untranslated definition instead of the pair */ pnt code2def(pnt term){ return HEAD(code2pair(term));} void record_pattern1(pnt caches,pnt def){ pnt lhs=term2arg2(def); pnt ref=term2ref(lhs); pnt idx=term2idx(lhs); pnt arg=tail(lhs); pnt rhs=term2arg3(def); pnt i; pnt name=nameget(caches,ref,idx); if(name==T) return; for(i=0;i