summaryrefslogtreecommitdiff
path: root/new
diff options
context:
space:
mode:
Diffstat (limited to 'new')
-rw-r--r--new/big.c643
-rw-r--r--new/data.c1250
-rw-r--r--new/lex.c1213
-rw-r--r--new/reduce.c2376
-rw-r--r--new/rules.y1686
-rw-r--r--new/steer.c2208
-rw-r--r--new/trans.c1026
-rw-r--r--new/types.c1613
8 files changed, 0 insertions, 12015 deletions
diff --git a/new/big.c b/new/big.c
deleted file mode 100644
index 7a1cfe1..0000000
--- a/new/big.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/* MIRANDA INTEGER PACKAGE */
-/* package for unbounded precision integers */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-#include "data.h"
-#include "big.h"
-#include <errno.h>
-
-static double logIBASE,log10IBASE;
-word big_one;
-
-void bigsetup()
-{ logIBASE=log((double)IBASE);
- log10IBASE=log10((double)IBASE);
- big_one=make(INT,1,0);
-}
-
-word isnat(x)
-word x;
-{ return(tag[x]==INT&&poz(x));
-}
-
-word sto_word(i) /* store C long long as mira bigint */
-long long i;
-{ word s,x;
- if(i<0)s=SIGNBIT,i= -i; else s=0;
- x=make(INT,s|i&MAXDIGIT,0);
- if(i>>=DIGITWIDTH)
- { word *p = &rest(x);
- *p=make(INT,i&MAXDIGIT,0),p= &rest(*p);
- while(i>>=DIGITWIDTH)
- *p=make(INT,i&MAXDIGIT,0),p= &rest(*p); }
- return(x);
-} /* change to long long, DT Oct 2019 */
-
-#define maxval (1ll<<60)
-
-long long get_word(x) /* mira bigint to C long long */
-word x;
-{ long long n=digit0(x);
- word sign=neg(x);
- if(!(x=rest(x)))return(sign?-n:n);
-{ word w=DIGITWIDTH;
- while(x&&w<60)n+=(long long)digit(x)<<w,w+=DIGITWIDTH,x=rest(x);
- if(x)n=maxval; /* overflow, return large value */
- return(sign?-n:n);
-}} /* change to long long, DT Oct 2019 */
-
-word bignegate(x)
-word x;
-{ if(bigzero(x))return(x);
- return(make(INT,hd[x]&SIGNBIT?hd[x]&MAXDIGIT:SIGNBIT|hd[x],tl[x]));
-}
-
-word bigplus(x,y)
-word x,y;
-{ if(poz(x))
- if(poz(y))return(big_plus(x,y,0));
- else return(big_sub(x,y));
- else
- if(poz(y))return(big_sub(y,x));
- else return(big_plus(x,y,SIGNBIT)); /* both negative */
-}
-
-word big_plus(x,y,signbit) /* ignore input signs, treat x,y as positive */
-word x,y; word signbit;
-{ word d=digit0(x)+digit0(y);
- word carry = ((d&IBASE)!=0);
- word r = make(INT,signbit|d&MAXDIGIT,0); /* result */
- word *z = &rest(r); /* pointer to rest of result */
- x = rest(x); y = rest(y);
- while(x&&y) /* this loop has been unwrapped once, see above */
- { d = carry+digit(x)+digit(y);
- carry = ((d&IBASE)!=0);
- *z = make(INT,d&MAXDIGIT,0);
- x = rest(x); y = rest(y); z = &rest(*z); }
- if(y)x=y; /* by convention x is the longer one */
- while(x)
- { d = carry+digit(x);
- carry = ((d&IBASE)!=0);
- *z = make(INT,d&MAXDIGIT,0);
- x = rest(x); z = &rest(*z); }
- if(carry)*z=make(INT,1,0);
- return(r);
-}
-
-word bigsub(x,y)
-word x,y;
-{ if(poz(x))
- if(poz(y))return(big_sub(x,y));
- else return(big_plus(x,y,0)); /* poz x, negative y */
- else
- if(poz(y))return(big_plus(x,y,SIGNBIT)); /* negative x, poz y */
- else return(big_sub(y,x)); /* both negative */
-}
-
-word big_sub(x,y) /* ignore input signs, treat x,y as positive */
-word x,y;
-{ word d = digit0(x)-digit0(y);
- word borrow = (d&IBASE)!=0;
- word r=make(INT,d&MAXDIGIT,0); /* result */
- word *z = &rest(r);
- word *p=NULL; /* pointer to trailing zeros, if any */
- x = rest(x); y = rest(y);
- while(x&&y) /* this loop has been unwrapped once, see above */
- { d = digit(x)-digit(y)-borrow;
- borrow = (d&IBASE)!=0;
- d = d&MAXDIGIT;
- *z = make(INT,d,0);
- if(d)p=NULL; else if(!p)p=z;
- x = rest(x); y = rest(y); z = &rest(*z); }
- while(y) /* at most one of these two loops will be invoked */
- { d = -digit(y)-borrow;
- borrow = ((d&IBASE)!=0);
- d = d&MAXDIGIT;
- *z = make(INT,d,0);
- if(d)p=NULL; else if(!p)p=z;
- y = rest(y); z = &rest(*z); }
- while(x) /* alternative loop */
- { d = digit(x)-borrow;
- borrow = ((d&IBASE)!=0);
- d = d&MAXDIGIT;
- *z = make(INT,d,0);
- if(d)p=NULL; else if(!p)p=z;
- x = rest(x); z = &rest(*z); }
- if(borrow) /* result is negative - take complement and add 1 */
- { p=NULL;
- d = (digit(r)^MAXDIGIT) + 1;
- borrow = ((d&IBASE)!=0); /* borrow now means `carry' (sorry) */
- digit(r) = SIGNBIT|d; /* set sign bit of result */
- z = &rest(r);
- while(*z)
- { d = (digit(*z)^MAXDIGIT)+borrow;
- borrow = ((d&IBASE)!=0);
- digit(*z) = d = d&MAXDIGIT;
- if(d)p=NULL; else if(!p)p=z;
- z = &rest(*z); }
- }
- if(p)*p=0; /* remove redundant (ie trailing) zeros */
- return(r);
-}
-
-word bigcmp(x,y) /* returns +ve,0,-ve as x greater than, equal, less than y */
-word x,y;
-{ word d,r,s=neg(x);
- if(neg(y)!=s)return(s?-1:1);
- r=digit0(x)-digit0(y);
- for(;;)
- { x=rest(x); y=rest(y);
- if(!x)if(y)return(s?1:-1);
- else return(s?-r:r);
- if(!y)return(s?-1:1);
- d=digit(x)-digit(y);
- if(d)r=d; }
-}
-
-word bigtimes(x,y) /* naive multiply - quadratic */
-word x,y;
-{ if(len(x)<len(y))
- { word hold=x; x=y; y=hold; } /* important optimisation */
- word r=make(INT,0,0);
- word d = digit0(y);
- word s=neg(y);
- word n=0;
- if(bigzero(x))return(r); /* short cut */
- for(;;)
- { if(d)r = bigplus(r,shift(n,stimes(x,d)));
- n++;
- y = rest(y);
- if(!y)
- return(s!=neg(x)?bignegate(r):r);
- d=digit(y); }
-}
-
-
-word shift(n,x) /* multiply big x by n'th power of IBASE */
-word n,x;
-{ while(n--)x=make(INT,0,x);
- return(x);
-} /* NB - we assume x non-zero, else unnormalised result */
-
-word stimes(x,n) /* multiply big x (>=0) by digit n (>0) */
-word x,n;
-{ unsigned d= n*digit0(x); /* ignore sign of x */
- word carry=d>>DIGITWIDTH;
- word r = make(INT,d&MAXDIGIT,0);
- word *y = &rest(r);
- while(x=rest(x))
- d=n*digit(x)+carry,
- *y=make(INT,d&MAXDIGIT,0),
- y = &rest(*y),
- carry=d>>DIGITWIDTH;
- if(carry)*y=make(INT,carry,0);
- return(r);
-}
-
-word b_rem; /* contains remainder from last call to longdiv or shortdiv */
-
-word bigdiv(x,y) /* may assume y~=0 */
-word x,y;
-{ word s1,s2,q;
- /* make x,y positive and remember signs */
- if(s1=neg(y))y=make(INT,digit0(y),rest(y));
- if(neg(x))
- x=make(INT,digit0(x),rest(x)),s2=!s1;
- else s2=s1;
- /* effect: s1 set iff y negative, s2 set iff signs mixed */
- if(rest(y))q=longdiv(x,y);
- else q=shortdiv(x,digit(y));
- if(s2){ if(!bigzero(b_rem))
- { x=q;
- while((digit(x)+=1)==IBASE) /* add 1 to q in situ */
- { digit(x)=0;
- if(!rest(x)){ rest(x)=make(INT,1,0); break; }
- else x=rest(x);
- }
- }
- if(!bigzero(q))digit(q)=SIGNBIT|digit(q);
- }
- return(q);
-}
-
-word bigmod(x,y) /* may assume y~=0 */
-word x,y;
-{ word s1,s2;
- /* make x,y positive and remember signs */
- if(s1=neg(y))y=make(INT,digit0(y),rest(y));
- if(neg(x))
- x=make(INT,digit0(x),rest(x)),s2=!s1;
- else s2=s1;
- /* effect: s1 set iff y negative, s2 set iff signs mixed */
- if(rest(y))longdiv(x,y);
- else shortdiv(x,digit(y));
- if(s2){ if(!bigzero(b_rem))
- b_rem = bigsub(y,b_rem);
- }
- return(s1?bignegate(b_rem):b_rem);
-}
-
-/* NB - above have entier based handling of signed cases (as Miranda) in
- which remainder has sign of divisor. To get this:- if signs of
- divi(sor/dend) mixed negate quotient and if remainder non-zero take
- complement and add one to magnitude of quotient */
-
-/* for alternative, truncate based handling of signed cases (usual in C):-
- magnitudes invariant under change of sign, remainder has sign of
- dividend, quotient negative if signs of divi(sor/dend) mixed */
-
-word shortdiv(x,n) /* divide big x by single digit n returning big quotient
- and setting external b_rem as side effect */
- /* may assume - x>=0,n>0 */
-word x,n;
-{ word d=digit(x),s_rem,q=0;
- while(x=rest(x)) /* reverse rest(x) into q */
- q=make(INT,d,q),d=digit(x); /* leaving most sig. digit in d */
- { word tmp;
- x=q; s_rem=d%n; d=d/n;
- if(d||!q)q=make(INT,d,0); /* put back first digit (if not leading 0) */
- else q=0;
- while(x) /* in situ division of q by n AND destructive reversal */
- d=s_rem*IBASE+digit(x),digit(x)=d/n,s_rem=d%n,
- tmp=x,x=rest(x),rest(tmp)=q,q=tmp;
- }
- b_rem=make(INT,s_rem,0);
- return(q);
-}
-
-word longdiv(x,y) /* divide big x by big y returning quotient, leaving
- remainder in extern variable b_rem */
- /* may assume - x>=0,y>0 */
-word x,y;
-{ word n,q,ly,y1,scale;
- if(bigcmp(x,y)<0){ b_rem=x; return(make(INT,0,0)); }
- y1=msd(y);
- if((scale=IBASE/(y1+1))>1) /* rescale if necessary */
- x=stimes(x,scale),y=stimes(y,scale),y1=msd(y);
- n=q=0;ly=len(y);
- while(bigcmp(x,y=make(INT,0,y))>=0)n++;
- y=rest(y); /* want largest y not exceeding x */
- ly += n;
- for(;;)
- { word d,lx=len(x);
- if(lx<ly)d=0; else
- if(lx==ly)
- if(bigcmp(x,y)>=0)x=bigsub(x,y),d=1;
- else d=0;
- else{ d=ms2d(x)/y1;
- if(d>MAXDIGIT)d=MAXDIGIT;
- if((d -= 2)>0)x=bigsub(x,stimes(y,d));
- else d=0;
- if(bigcmp(x,y)>=0)
- { x=bigsub(x,y),d++;
- if(bigcmp(x,y)>=0)
- x=bigsub(x,y),d++; }
- }
- q = make(INT,d,q);
- if(n-- ==0)
- { b_rem = scale==1?x:shortdiv(x,scale); return(q); }
- ly-- ; y = rest(y); }
-} /* see Bird & Wadler p82 for explanation */
-
-word len(x) /* no of digits in big x */
-word x;
-{ word n=1;
- while(x=rest(x))n++;
- return(n);
-}
-
-word msd(x) /* most significant digit of big x */
-word x;
-{ while(rest(x))x=rest(x);
- return(digit(x)); /* sign? */
-}
-
-word ms2d(x) /* most significant 2 digits of big x (len>=2) */
-word x;
-{ word d=digit(x);
- x=rest(x);
- while(rest(x))d=digit(x),x=rest(x);
- return(digit(x)*IBASE+d);
-}
-
-word bigpow(x,y) /* assumes y poz */
-word x,y;
-{ word d,r=make(INT,1,0);
- while(rest(y)) /* this loop has been unwrapped once, see below */
- { word i=DIGITWIDTH;
- d=digit(y);
- while(i--)
- { if(d&1)r=bigtimes(r,x);
- x = bigtimes(x,x);
- d >>= 1; }
- y=rest(y);
- }
- d=digit(y);
- if(d&1)r=bigtimes(r,x);
- while(d>>=1)
- { x = bigtimes(x,x);
- if(d&1)r=bigtimes(r,x); }
- return(r);
-}
-
-double bigtodbl(x)
-word x;
-{ word s=neg(x);
- double b=1.0, r=(double)digit0(x);
- x = rest(x);
- while(x)b=b*IBASE,r=r+b*digit(x),x=rest(x);
- if(s)return(-r);
- return(r);
-} /* small end first */
-/* note: can return oo, -oo
- but is used without surrounding sto_/set)dbl() only in compare() */
-
-/* not currently used
-long double bigtoldbl(x)
-word x;
-{ int s=neg(x);
- long double b=1.0L, r=digit0(x);
- x = rest(x);
- while(x)b=b*IBASE,r=r+b*digit(x),x=rest(x);
-/*printf("bigtoldbl returns %Le\n",s?-r:r); /* DEBUG
- if(s)return(-r);
- return(r);
-} /* not compatible with std=c90, lib fns eg sqrtl broken */
-
-word dbltobig(x) /* entier */
-double x;
-{ word s= (x<0);
- word r=make(INT,0,0);
- word *p = &r;
- double y= floor(x);
-/*if(fabs(y-x+1.0)<1e-9)y += 1.0; /* trick due to Peter Bartke, see note */
- for(y=fabs(y);;)
- { double n = fmod(y,(double)IBASE);
- digit(*p) = (word)n;
- y = (y-n)/(double)IBASE;
- if(y>0.0)rest(*p)=make(INT,0,0),p=&rest(*p);
- else break;
- }
- if(s)digit(r)=SIGNBIT|digit(r);
- return(r);
-}
-/* produces junk in low order digits if x exceeds range in which integer
- can be held without error as a double -- NO, see next comment */
-/* hugs, ghci, mira produce same integer for floor/entier hugenum, has 2^971
- as factor so the low order bits are NOT JUNK -- 9.1.12 */
-
-/* note on suppressed fix:
- choice of 1e9 arbitrary, chosen to prevent eg entier(100*0.29) = 28
- but has undesirable effects, causing eg entier 1.9999999999 = 2
- underlying problem is that computable floor on true Reals is _|_ at
- the exact integers. There are inherent deficiences in 64 bit fp,
- no point in trying to mask this */
-
-double biglog(x) /* logarithm of big x */
-word x;
-{ word n=0;
- double r=digit(x);
- if(neg(x)||bigzero(x))errno=EDOM,math_error("log");
- while(x=rest(x))n++,r=digit(x)+r/IBASE;
- return(log(r)+n*logIBASE);
-}
-
-double biglog10(x) /* logarithm of big x */
-word x;
-{ word n=0;
- double r=digit(x);
- if(neg(x)||bigzero(x))errno=EDOM,math_error("log10");
- while(x=rest(x))n++,r=digit(x)+r/IBASE;
- return(log10(r)+n*log10IBASE);
-}
-
-word bigscan(p) /* read a big number (in decimal) */
- /* NB does NOT check for malformed number, assumes already done */
-char *p; /* p is a pointer to a null terminated string of digits */
-{ word s=0,r=make(INT,0,0);
- if(*p=='-')s=1,p++; /* optional leading `-' (for NUMVAL) */
- while(*p)
- { word d= *p-'0',f=10;
- p++;
- while(*p&&f<PTEN)d=10*d+*p-'0',f=10*f,p++;
- /* rest of loop does r=f*r+d; (in situ) */
- d= f*digit(r)+d;
- { word carry=d>>DIGITWIDTH;
- word *x = &rest(r);
- digit(r)=d&MAXDIGIT;
- while(*x)
- d=f*digit(*x)+carry,
- digit(*x)=d&MAXDIGIT,
- carry=d>>DIGITWIDTH,
- x = &rest(*x);
- if(carry)*x=make(INT,carry,0);
- }}
-/*if(*p=='e')
- { int s=bigscan(p+1);
- r = bigtimes(r,bigpow(make(INT,10,0),s); } */
- if(s&&!bigzero(r))digit(r)=digit(r)|SIGNBIT;
- return(r);
-}
-/* code to handle (unsigned) exponent commented out */
-
-word bigxscan(p,q) /* read unsigned hex number in '\0'-terminated string p to q */
- /* assumes redundant leading zeros removed */
-char *p, *q;
-{ word r; /* will hold result */
- word *x = &r;
- if(*p=='0'&&!p[1])return make(INT,0,0);
- while(q>p)
- { unsigned long long hold;
- q = q-p<15 ? p : q-15; /* read upto 15 hex digits from small end */
- sscanf(q,"%llx",&hold);
- *q = '\0';
- word count=4; /* 15 hex digits => 4 bignum digits */
- while(count-- && !(hold==0 && q==p))
- *x = make(INT,hold&MAXDIGIT,0),
- hold >>= DIGITWIDTH,
- x = &rest(*x);
- }
- return r;
-}
-
-word bigoscan(p,q) /* read unsigned octal number in '\0'-terminated string p to q */
- /* assumes redundant leading zeros removed */
-char *p, *q;
-{ word r; /* will hold result */
- word *x = &r;
- while(q>p)
- { unsigned word hold;
- q = q-p<5 ? p : q-5; /* read (upto) 5 octal digits from small end */
- sscanf(q,"%o",&hold);
- *q = '\0';
- *x = make(INT,hold,0),
- x = &rest(*x);
- }
- return r;
-}
-
-word digitval(c)
-char c;
-{ return isdigit(c)?c-'0':
- isupper(c)?10+c-'A':
- 10+c-'a'; }
-
-word strtobig(z,base) /* numeral (as Miranda string) to big number */
- /* does NOT check for malformed numeral, assumes
- done and that z fully evaluated */
-word z; word base;
-{ word s=0,r=make(INT,0,0),PBASE=PTEN;
- if(base==16)PBASE=PSIXTEEN; else
- if(base==8)PBASE=PEIGHT;
- if(z!=NIL&&hd[z]=='-')s=1,z=tl[z]; /* optional leading `-' (for NUMVAL) */
- if(base!=10)z=tl[tl[z]]; /* remove "0x" or "0o" */
- while(z!=NIL)
- { word d=digitval(hd[z]),f=base;
- z=tl[z];
- while(z!=NIL&&f<PBASE)d=base*d+digitval(hd[z]),f=base*f,z=tl[z];
- /* rest of loop does r=f*r+d; (in situ) */
- d= f*digit(r)+d;
- { word carry=d>>DIGITWIDTH;
- word *x = &rest(r);
- digit(r)=d&MAXDIGIT;
- while(*x)
- d=f*digit(*x)+carry,
- digit(*x)=d&MAXDIGIT,
- carry=d>>DIGITWIDTH,
- x = &rest(*x);
- if(carry)*x=make(INT,carry,0);
- }}
- if(s&&!bigzero(r))digit(r)=digit(r)|SIGNBIT;
- return(r);
-}
-
-extern char *dicp;
-
-word bigtostr(x) /* number to decimal string (as Miranda list) */
-word x;
-{ word x1,sign,s=NIL;
-#ifdef DEBUG
- extern word debug;
- if(debug&04) /* print octally */
- { word d=digit0(x);
- sign=neg(x);
- for(;;)
- { word i=OCTW;
- while(i--||d)s=cons('0'+(d&07),s),d >>= 3;
- x=rest(x);
- if(x)s=cons(' ',s),d=digit(x);
- else return(sign?cons('-',s):s); }
- }
-#endif
- if(rest(x)==0)
- { extern char *dicp;
- sprintf(dicp,"%d",getsmallint(x));
- return(str_conv(dicp)); }
- sign=neg(x);
- x1=make(INT,digit0(x),0); /* reverse x into x1 */
- while(x=rest(x))x1=make(INT,digit(x),x1);
- x=x1;
- for(;;)
- { /* in situ division of (reversed order) x by PTEN */
- word d=digit(x),rem=d%PTEN;
- d=d/PTEN; x1=rest(x);
- if(d)digit(x)=d;
- else x=x1; /* remove leading zero from result */
- while(x1)
- d=rem*IBASE+digit(x1),
- digit(x1)=d/PTEN,
- rem=d%PTEN,
- x1=rest(x1);
- /* end of in situ division (also uses x1 as temporary) */
- if(x)
- { word i=TENW;
- while(i--)s=cons('0'+rem%10,s),rem=rem/10; }
- else
- { while(rem)s=cons('0'+rem%10,s),rem=rem/10;
- return(sign?cons('-',s):s); }
- }
-}
-
-word bigtostrx(x) /* integer to hexadecimal string (as Miranda list) */
-word x;
-{ word r=NIL, s=neg(x);
- while(x)
- { word count=4; /* 60 bits => 20 octal digits => 4 bignum digits */
- unsigned long long factor=1;
- unsigned long long hold=0;
- while(count-- && x) /* calculate value of (upto) 4 bignum digits */
- hold=hold+factor*digit0(x),
- /* printf("::%llx\n",hold), /* DEBUG */
- factor<<=15,
- x=rest(x);
- sprintf(dicp,"%.15llx",hold); /* 15 hex digits = 60 bits */
- /* printf(":::%s\n",dicp); /* DEBUG */
- char *q=dicp+15;
- while(--q>=dicp)r = cons(*q,r);
- }
- while(digit(r)=='0'&&rest(r)!=NIL)r=rest(r); /* remove redundant leading 0's */
- r = cons('0',cons('x',r));
- if(s)r = cons('-',r);
- return(r);
-}
-
-word bigtostr8(x) /* integer to octal string (as Miranda list) */
-word x;
-{ word r=NIL, s=neg(x);
- while(x)
- { char *q = dicp+5;
- sprintf(dicp,"%.5o",digit0(x));
- while(--q>=dicp)r = cons(*q,r);
- x = rest(x); }
- while(digit(r)=='0'&&rest(r)!=NIL)r=rest(r); /* remove redundant leading 0's */
- r = cons('0',cons('o',r));
- if(s)r = cons('-',r);
- return(r);
-}
-
-#ifdef DEBUG
-wff(x) /* check for well-formation of integer */
-word x;
-{ word y=x;
- if(tag[x]!=INT)printf("BAD TAG %d\n",tag[x]);
- if(neg(x)&&!digit0(x)&&!rest(x))printf("NEGATIVE ZERO!\n");
- if(digit0(x)&(~MAXDIGIT))printf("OVERSIZED DIGIT!\n");
- while(x=rest(x))
- if(tag[x]!=INT)printf("BAD INTERNAL TAG %d\n",tag[x]); else
- if(digit(x)&(~MAXDIGIT))
- printf("OVERSIZED DIGIT!\n"); else
- if(!digit(x)&&!rest(x))
- printf("TRAILING ZERO!\n");
- return(y);
-}
-
-normalise(x) /* remove trailing zeros */
-word x;
-{ if(rest(x))rest(x)=norm1(rest(x));
- return(wff(x));
-}
-
-norm1(x)
-word x;
-{ if(rest(x))rest(x)=norm1(rest(x));
- return(!digit(x)&&!rest(x)?0:x);
-}
-
-#endif
-
-/* stall(s)
-char *s;
-{ fprintf(stderr,"big integer %s not yet implemented\n",s);
- exit(0);
-}
-
-#define destrev(x,y,z) while(x)z=x,x=rest(x),rest(z)=y,y=z;
-/* destructively reverse x into y using z as temp */
-
-/* END OF MIRANDA INTEGER PACKAGE */
-
diff --git a/new/data.c b/new/data.c
deleted file mode 100644
index c7463ac..0000000
--- a/new/data.c
+++ /dev/null
@@ -1,1250 +0,0 @@
-/* MIRANDA DATA REPRESENTATIONS */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-#include "data.h"
-#include "big.h"
-#define INITSPACE 250000
-word SPACE=INITSPACE; /* false ceiling in heap to improve paging behaviour
- during compilation */
-extern word SPACELIMIT; /* see steer.c for default value */
- /* SPACELIMIT controls the size of the heap (i.e. the number of list
- cells available) - the minimum survivable number given the need to
- compile the prelude etc is probably about 6000 */
- /* Note: the size of a list cell is 2 ints + 1 char */
-#define BIGTOP (SPACELIMIT + ATOMLIMIT)
-word listp=ATOMLIMIT-1;
-word *hdspace,*tlspace;
-long long cellcount=0;
-long claims=0;
-long nogcs=0;
-extern word atgc; /* flag, set in steer.c */
-#define poschar(c) !(negchar((c)-1))
-#define negchar(c) (c&128)
- /* safest to test for -ve chars this way, since not all m/c's do sign
- extension - DT Jan 84 */
-
-trueheapsize()
-{ return(nogcs==0?listp-ATOMLIMIT+1:SPACE); }
-
-setupheap()
-{ hdspace=(word *)malloc(SPACELIMIT*sizeof(word));
- tlspace=(word *)malloc(SPACELIMIT*sizeof(word));
- hd=hdspace-ATOMLIMIT; tl=tlspace-ATOMLIMIT;
- if(SPACE>SPACELIMIT)SPACE=SPACELIMIT;
- tag=(char *)calloc(BIGTOP+1,sizeof(char));
- /* NB use calloc because it sets contents to zero */
- /* tag[TOP] must be zero and exists as a sentinel */
- if(hdspace==NULL||tlspace==NULL||tag==NULL)mallocfail("heap");
-}
-
-resetheap() /* warning - cannot do this dynamically, because both the
- compiler and the reducer hold onto absolute heap addresses
- during certain space consuming computations */
-{ if(SPACELIMIT<trueheapsize())
- fprintf(stderr,"impossible event in resetheap\n"),exit(1);
- hdspace=(word *)realloc((char *)hdspace,SPACELIMIT*sizeof(word));
- if(hdspace==NULL)mallocfail("heap");
- tlspace=(word *)realloc((char *)tlspace,SPACELIMIT*sizeof(word));
- if(tlspace==NULL)mallocfail("heap");
- hd=hdspace-ATOMLIMIT; tl=tlspace-ATOMLIMIT;
- tag=(char *)realloc(tag,BIGTOP+1);
- if(tag==NULL)mallocfail("heap");
- tag[BIGTOP]=0;
- if(SPACE>SPACELIMIT)SPACE=SPACELIMIT;
- if(SPACE<INITSPACE&&INITSPACE<=SPACELIMIT)SPACE=INITSPACE,tag[TOP]=0;
- /* tag[TOP] is always zero and exists as a sentinel */
-}
-
-mallocfail(x)
-char *x;
-{ fprintf(stderr,"panic: cannot find enough free space for %s\n",x);
- exit(1);
-}
-
-resetgcstats()
-{ cellcount= -claims;
- nogcs = 0;
- initclock();
-}
-
-make(t,x,y) /* creates a new cell with "tag" t, "hd" x and "tl" y */
-word t,x,y;
-{ while(poschar(tag[++listp]));
- /* find next cell with zero or negative tag (=unwanted) */
- if(listp==TOP)
- { if(SPACE!=SPACELIMIT)
- if(!compiling)SPACE=SPACELIMIT; else
- if(claims<=SPACE/4&&nogcs>1)
- { /* during compilation we raise false ceiling whenever residency
- reaches 75% on 2 successive gc's */
- static word wait=0;
- word sp=SPACE;
- if(wait)wait--; else
- SPACE+= SPACE/2,wait=2,
- SPACE=5000*(1+(SPACE-1)/5000); /* round upwards */
- if(SPACE>SPACELIMIT)SPACE=SPACELIMIT;
- if(atgc&&SPACE>sp)
- printf( "\n<<increase heap from %d to %d>>\n",sp,SPACE);
- }
- if(listp==TOP)
- {
-#if defined ORION105
- asm("savew6");
- gc();
- asm("restw6");
-#elif defined sparc
- asm("ta 0x03"); /* see /usr/include/sun4/trap.h */
- /* asm("ta ST_FLUSH_WINDOWS"); */
- gc();
-#else
- gc();
-#endif
- if(t>STRCONS)mark(x);
- if(t>=INT)mark(y);
- return(make(t,x,y)); }
- }
- claims++;
- tag[listp]= t;
- hd[listp]= x;
- tl[listp]= y;
- return(listp); }
-
-/* cons ap ap2 ap3 are all #defined in terms of make
- - see MIRANDA DECLARATIONS */
-
-setwd(x,a,b)
-word x,a,b;
-{ hd[x]= a;
- tl[x]= b; }
-
-word collecting=0; /* flag for reset(), in case interrupt strikes in gc */
-
-gc() /* the "garbage collector" */
-{ char *p1;
- extern word making;
- collecting=1;
- p1= &(tag[ATOMLIMIT]);
- if(atgc)
- printf("\n<<gc after %ld claims>>\n",claims);
- if(claims<=SPACE/10 && nogcs>1 && SPACE==SPACELIMIT)
- { /* if heap utilisation exceeds 90% on 2 successive gc's, give up */
- static word hnogcs=0;
- if(nogcs==hnogcs)
- { extern word ideep;
- extern char *current_script;
- fprintf(stderr,"<<not enough heap space -- task abandoned>>\n");
- if(!compiling)outstats();
- if(compiling&&ideep==0)
- fprintf(stderr,"not enough heap to compile current script\n"),
- fprintf(stderr,"script = \"%s\", heap = %d\n",current_script,SPACE);
- exit(1); } /* if compiling should reset() instead - FIX LATER */
- else hnogcs=nogcs+1; }
- nogcs++;
- while(*p1= -*p1)p1++; /* make all tags -ve (= unwanted) */
-/*if(atgc)
- { extern int lasthead;
-#define BACKSTOP 020000000000
- printf("bases() called\n");
- printf("lasthead= ");
- if(lasthead==BACKSTOP)printf("BACKSTOP");
- else out(stdout,lasthead);
- putchar('\n'); } /* DEBUG */
- bases();
-/*if(atgc)printf("bases() done\n"); /* DEBUG */
- listp= ATOMLIMIT - 1;
- cellcount+= claims;
- claims= 0;
- collecting=0;
-}
-/* int Icount; /* DEBUG */
-
-gcpatch() /* called when gc interrupted - see reset in steer.c */
-/* must not allocate any cells between calling this and next gc() */
-{ char *p1;
- for(p1= &(tag[ATOMLIMIT]);*p1;p1++)if(negchar(*p1))*p1= -*p1;
- /* otherwise mutator crashes on funny tags */
-}
-
-bases() /* marks everthing that must be saved */
-{ word *p;
- extern YYSTYPE yyval;
- extern word *cstack;
- extern word fileq,primenv;
- extern word cook_stdin,common_stdin,common_stdinb,rv_expr,rv_script;
- extern word margstack,vergstack,litstack,linostack,prefixstack;
- extern word idsused,suppressids,lastname,
- eprodnts,nonterminals,ntmap,ihlist,ntspecmap,gvars,lexvar;
- extern word R,TABSTRS,SGC,ND,SBND,NT,current_id,meta_pending;
- extern word showchain,newtyps,algshfns,errs,speclocs;
- extern word SUBST[],tvmap,localtvmap;
- extern word tfnum,tfbool,tfbool2,tfnum2,tfstrstr,
- tfnumnum,ltchar,bnf_t,tstep,tstepuntil;
- extern word exec_t,read_t,filestat_t;
- extern word big_one;
- extern word nill,standardout;
- extern word lexstates,lexdefs,oldfiles,includees,embargoes,exportfiles,
- exports,internals, freeids,tlost,detrop,rfl,bereaved,ld_stuff;
- extern word CLASHES,ALIASES,SUPPRESSED,TSUPPRESSED,DETROP,MISSING,fnts,FBS;
- extern word outfilq,waiting;
- /* Icount=0; /* DEBUG */
- p= (word *)&p;
-/* we follow everything on the C stack that looks like a pointer into
-list space. This is failsafe in that the worst that can happen,if e.g. a
-stray integer happens to point into list space, is that the garbage
-collector will collect less garbage than it could have done */
- if(p<cstack) /* which way does stack grow? */
- while(++p!=cstack)mark(*p);/* for machines with stack growing downwards */
- else
- while(--p!=cstack)mark(*p);/* for machines with stack growing upwards */
- mark(*cstack);
-/* now follow all pointer-containing external variables */
- mark(outfilq);
- mark(waiting);
- if(compiling||rv_expr||rv_script) /* rv flags indicate `readvals' in use */
- { extern YYSTYPE *yyvs, *yyvsp;
- extern word namebucket[];
- extern word *dstack,*stackp; /* undump stack - see load_script(), below */
- extern word *pnvec,nextpn,loading; /* private name vector */
- extern word make_status;
- word i;
- mark(make_status);
- mark(primenv);
- mark(fileq);
- mark(idsused);
- mark(eprodnts);
- mark(nonterminals);
- mark(ntmap);
- mark(ihlist);
- mark(ntspecmap);
- mark(gvars);
- mark(lexvar);
- mark(common_stdin);
- mark(common_stdinb);
- mark(cook_stdin);
- mark(margstack);
- mark(vergstack);
- mark(litstack);
- mark(linostack);
- mark(prefixstack);
- mark(files);
- mark(oldfiles);
- mark(includees);
- mark(freeids);
- mark(exports);
- mark(internals);
- mark(CLASHES);
- mark(ALIASES);
- mark(SUPPRESSED);
- mark(TSUPPRESSED);
- mark(DETROP);
- mark(MISSING);
- mark(FBS);
- mark(lexstates);
- mark(lexdefs);
- for(i=0;i<128;i++)
- if(namebucket[i])mark(namebucket[i]);
- for(p=dstack;p<stackp;p++)mark(*p);
- if(loading)
- { mark(algshfns);
- mark(speclocs);
- mark(exportfiles);
- mark(embargoes);
- mark(rfl);
- mark(detrop);
- mark(bereaved);
- mark(ld_stuff);
- mark(tlost);
- for(i=0;i<nextpn;i++)mark(pnvec[i]); }
- mark(lastname);
- mark(suppressids);
- mark(lastexp);
- mark(nill);
- mark(standardout);
- mark(big_one);
- mark(yyval);
-/* for(vp= yyvs;vp<=yyvsp;vp++)mark(*vp); */
- mark(yylval);
- mark(R);
- mark(TABSTRS);
- mark(SGC);
- mark(ND);
- mark(SBND);
- mark(NT);
- mark(current_id);
- mark(meta_pending);
- mark(newtyps);
- mark(showchain);
- mark(errs);
- mark(tfnum);
- mark(tfbool);
- mark(tfbool2);
- mark(tfnum2);
- mark(tfstrstr);
- mark(tfnumnum);
- mark(ltchar);
- mark(bnf_t);
- mark(exec_t);
- mark(read_t);
- mark(filestat_t);
- mark(tstep);
- mark(tstepuntil);
- mark(tvmap);
- mark(localtvmap);
- for(i=0;i<hashsize;i++)mark(SUBST[i]); }
-/* if(atgc)printf("<<%d I-nodes>>\n",Icount); /* DEBUG */
-}
-
-#define tlptrbits 030000000000
-/* see reduce.c */
-
-mark(x) /* a marked cell is distinguished by having a +ve "tag" */
-word x;
-{ x&= ~tlptrbits; /* x may be a `reversed pointer' (see reduce.c) */
- while(isptr(x)&&negchar(tag[x]))
- { /*if(hd[x]==I)Icount++; /* DEBUG */
- if((tag[x]= -tag[x])<INT)return;
- if(tag[x]>STRCONS)mark(hd[x]);
- x= tl[x]&~tlptrbits; }
-}
-
-union numparts {double real; struct{word left;word right;} parts;};
-
-double get_dbl(x)
-word x;
-{ union numparts r;
- r.parts.left= hd[x];
- r.parts.right= tl[x];
- return(r.real); }
-
-/* Miranda's arithmetic model requires fp overflow trapped. On sparc this
- can be done by setting a trap with ieee_handler (see steer.c) otherwise
- we test for overflow with finite(), see IEEE754-1985 (Appendix) */
-
-sto_dbl(R)
-double R;
-{ union numparts r;
-#if !defined sparc /* */
- if(!finite(R))fpe_error(); /* see note on arithmetic model above */
-#endif /* */
- r.real=R;
- return(make(DOUBLE,r.parts.left,r.parts.right));
-}
-
-setdbl(x,R)
-double R;
-{ union numparts r;
-#if !defined sparc /* */
- if(!finite(R))fpe_error(); /* see note on arithmetic model above */
-#endif /* */
- r.real=R;
- tag[x]=DOUBLE; hd[x]=r.parts.left; tl[x]=r.parts.right;
-}
-
-sto_char(c) /* assumes 0<=c<=UMAX */
-word c;
-{ return c<256?c:make(UNICODE,c,0); }
-
-get_char(x)
-word x;
-{ if(x<256)return x;
- if(tag[x]==UNICODE)return hd[x];
- fprintf(stderr,"impossible event in get_char(x), tag[x]==%d\n",tag[x]);
- exit(1);
-}
-
-is_char(x)
-word x;
-{ return 0<=x && x<256 || tag[x]==UNICODE; }
-
-sto_id(p1)
-char *p1;
-{ return(make(ID,cons(strcons(p1,NIL),undef_t),UNDEF)); }
- /* the hd of an ID contains cons(strcons(name,who),type) and
- the tl has the value */
- /* who is NIL, hereinfo, or cons(aka,hereinfo) where aka
- is of the form datapair(oldname,0) oldname being a string */
- /* hereinfo is fileinfo(script,line_no) */
-
-/* hereafter is stuff for dumping and undumping compiled scripts
-
- (internal heap object) (external file rep - char sequence)
- ---------------------- -----------------------------------
- 0..127 self
- 128..383 CHAR_X (self-128)
- 384..ATOMLIMIT-1 (self-256)
- integer (-127..127) SHORT_X <byte>
- integer INT_X <4n bytes> (-1)
- double DBL_X <8 bytes>
- unicode_char UNICODE_X <4 bytes>
- typevar TVAR_X <byte>
- ap(x,y) [x] [y] AP_X
- cons(x,y) [y] [x] CONS_X
- id (=occurrence) ID_X <string terminated by '\0'>
- pname (=occurrence) PN_X <2 bytes>
- PN1_X <4 bytes>
- datapair(string,0) AKA_X <string...\0>
- fileinfo(script,line_no) HERE_X <string...\0> <2 bytes> (**)
- constructor(n,x) [x] CONSTRUCT_X <2 bytes>
- readvals(h,t) [t] RV_X
- definition [val] [type] [who] [id] DEF_X
- [val] [pname] DEF_X
- definition-list [definition*] DEF_X
- filename <string terminated by '\0'>
- mtime <4 bytes>
-
- complete script XVERSION
- [ [filename]
- [mtime]
- [shareable] (=0 or 1)
- [definition-list] ]+
- '\0'
- [definition-list] (algshfns)
- [ND] or [True] (see below)
- DEF_X
- [SGC]
- DEF_X
- [freeids]
- DEF_X
- [definition-list] (internals)
-
- type-error script XVERSION
- '\1'
- <4 bytes> (=errline)
- ... (rest as normal script)
-
- syntax-error script XVERSION
- `\0'
- <4 bytes> (=errline)
- [ [filename]
- [mtime] ]+
-
- Notes
- -----
- first filename in dump must be that of `current_script' (ie the
- main source file). All pathnames in dump are correct wrt the
- directory of the main source.
- (**) empty string is abbreviation for current filename in hereinfo
- True in ND position indicates an otherwise correct dump whose exports
- include type orphans
-
- Pending:
- --------
- could have abbreviation for iterated ap and cons
-
- remaining issue - external format should be machine and version
- independent - not clear how to do this
-*/
-
-#define XBASE ATOMLIMIT-256
-#define CHAR_X (XBASE)
-#define SHORT_X (XBASE+1)
-#define INT_X (XBASE+2)
-#define DBL_X (XBASE+3)
-#define ID_X (XBASE+4)
-#define AKA_X (XBASE+5)
-#define HERE_X (XBASE+6)
-#define CONSTRUCT_X (XBASE+7)
-#define RV_X (XBASE+8)
-#define PN_X (XBASE+9)
-#define PN1_X (XBASE+10)
-#define DEF_X (XBASE+11)
-#define AP_X (XBASE+12)
-#define CONS_X (XBASE+13)
-#define TVAR_X (XBASE+14)
-#define UNICODE_X (XBASE+15)
-#define XLIMIT (XBASE+16)
-#if XLIMIT>512
-SEE ME!!! /* coding scheme breaks down if this occurs */
-#else
-
-static char prefix[pnlim];
-word preflen;
-
-setprefix(p) /* to that of pathname p */
-char *p;
-{ char *g;
- (void)strcpy(prefix,p);
- g=rindex(prefix,'/');
- if(g)g[1]='\0';
- else *prefix='\0';
- preflen = strlen(prefix);
-} /* before calling dump_script or load_script must setprefix() to that
- of current pathname of file being dumped/loaded - to get correct
- translation between internal pathnames (relative to dump script)
- and external pathnames */
-
-char *mkrel(p) /* makes pathname p correct relative to prefix */
-char *p; /* must use when writing pathnames to dump */
-{ if(strncmp(prefix,p,preflen)==0)return(p+preflen);
- if(p[0]=='/')return(p);
- fprintf(stderr,"impossible event in mkrelative\n"); /* or use getwd */
- /* not possible because all relative pathnames in files were computed
- wrt current script */
- return(p); /* proforma only */
-}
-
-#define bits_15 0177777
-char *CFN;
-
-dump_script(files,f) /* write compiled script files to file f */
-word files;
-FILE *f;
-{ extern word ND,bereaved,errline,algshfns,internals,freeids,SGC;
- putc(XVERSION,f); /* identifies dump format */
- if(files==NIL){ /* source contains syntax or metatype error */
- extern word oldfiles;
- word x;
- putc(0,f);
- putw(errline,f);
- for(x=oldfiles;x!=NIL;x=tl[x])
- fprintf(f,"%s",mkrel(get_fil(hd[x]))),putc(0,f),
- /*filename*/
- putw(fil_time(hd[x]),f); /* mtime */
- return; }
- if(ND!=NIL)putc(1,f),putw(errline,f);
- for(;files!=NIL;files=tl[files])
- { fprintf(f,"%s",mkrel(CFN=get_fil(hd[files]))); /* filename */
- putc(0,f);
- putw(fil_time(hd[files]),f);
- putc(fil_share(hd[files]),f);
- dump_defs(fil_defs(hd[files]),f);
- }
- putc(0,f); /* header - not a possible filename */
- dump_defs(algshfns,f);
- if(ND==NIL&&bereaved!=NIL)dump_ob(True,f); /* special flag */
- else dump_ob(ND,f);
- putc(DEF_X,f);
- dump_ob(SGC,f);
- putc(DEF_X,f);
- dump_ob(freeids,f);
- putc(DEF_X,f);
- dump_defs(internals,f);
-}
-
-dump_defs(defs,f) /* write list of defs to file f */
-word defs;
-FILE *f;
-{ while(defs!=NIL)
- if(tag[hd[defs]]==STRCONS) /* pname */
- { word v=get_pn(hd[defs]);
- dump_ob(pn_val(hd[defs]),f);
- if(v>bits_15)
- putc(PN1_X,f),
- putw(v,f);
- else
- putc(PN_X,f),
- putc(v&255,f),
- putc(v >> 8,f);
- putc(DEF_X,f);
- defs=tl[defs]; }
- else
- { dump_ob(id_val(hd[defs]),f);
- dump_ob(id_type(hd[defs]),f);
- dump_ob(id_who(hd[defs]),f);
- putc(ID_X,f);
- fprintf(f,"%s",(char *)get_id(hd[defs]));
- putc(0,f);
- putc(DEF_X,f);
- defs=tl[defs]; }
- putc(DEF_X,f); /* delimiter */
-}
-
-dump_ob(x,f) /* write combinatory expression x to file f */
-word x;
-FILE *f;
-{ /* printob("dumping: ",x); /* DEBUG */
- switch(tag[x])
- { case ATOM: if(x<128)putc(x,f); else
- if(x>=384)putc(x-256,f); else
- putc(CHAR_X,f),putc(x-128,f);
- return;
- case TVAR: putc(TVAR_X,f), putc(gettvar(x),f);
- if(gettvar(x)>255)
- fprintf(stderr,"panic, tvar too large\n");
- return;
- case INT: { /* 32 bit version (suppressed)
- int d=get_int(x);
- if(abs(d)<=127)
- { putc(SHORT_X,f); putc(d,f); return; }
- putc(INT_X,f);
- putw(d,f);
- /* variable length version */
- word d=digit(x);
- if(rest(x)==0&&(d&MAXDIGIT)<=127)
- { if(d&SIGNBIT)d= -(d&MAXDIGIT);
- putc(SHORT_X,f); putc(d,f); return; }
- putc(INT_X,f);
- putw(d,f);
- x=rest(x);
- while(x)
- putw(digit(x),f),x=rest(x);
- putw(-1,f);
- /* end of variable length version */
- return; }
- /* 4 bytes per digit wasteful at current value of IBASE */
- case DOUBLE: putc(DBL_X,f);
- putw(hd[x],f);
- putw(tl[x],f);
- return;
- case UNICODE: putc(UNICODE_X,f);
- putw(hd[x],f);
- return;
- case DATAPAIR: fprintf(f,"%c%s",AKA_X,(char *)hd[x]);
- putc(0,f);
- return;
- case FILEINFO: { word line=tl[x];
- if((char *)hd[x]==CFN)putc(HERE_X,f);
- else fprintf(f,"%c%s",HERE_X,mkrel(hd[x]));
- putc(0,f);
- putc(line&255,f);
- putc((line >>= 8)&255,f);
- if(line>255)fprintf(stderr,
- "impossible line number %d in dump_ob\n",tl[x]);
- return; }
- case CONSTRUCTOR: dump_ob(tl[x],f);
- putc(CONSTRUCT_X,f);
- putc(hd[x]&255,f);
- putc(hd[x]>>8,f);
- return;
- case STARTREADVALS: dump_ob(tl[x],f);
- putc(RV_X,f);
- return;
- case ID: fprintf(f,"%c%s",ID_X,get_id(x));
- putc(0,f);
- return;
- case STRCONS: { word v=get_pn(x); /* private name */
- if(v>bits_15)
- putc(PN1_X,f),
- putw(v,f);
- else
- putc(PN_X,f),
- putc(v&255,f),
- putc(v >> 8,f);
- return; }
- case AP: dump_ob(hd[x],f);
- dump_ob(tl[x],f);
- putc(AP_X,f);
- return;
- case CONS: dump_ob(tl[x],f);
- dump_ob(hd[x],f);
- putc(CONS_X,f);
- return;
- default: fprintf(stderr,"impossible tag %d in dump_ob\n",tag[x]);
- }
-}
-
-#define ovflocheck if(dicq-dic>DICSPACE)dicovflo()
-extern char *dic; extern word DICSPACE;
-
-word BAD_DUMP=0,CLASHES=NIL,ALIASES=NIL,PNBASE=0,SUPPRESSED=NIL,
- TSUPPRESSED=NIL,TORPHANS=0;
-
-load_script(f,src,aliases,params,main)
- /* loads a compiled script from file f for source src */
- /* main=1 if is being loaded as main script, 0 otherwise */
-FILE *f;
-char *src;
-word aliases,params,main;
-{ extern word nextpn,ND,errline,algshfns,internals,freeids,includees,SGC;
- extern char *dicp, *dicq;
- word ch,files=NIL;
- TORPHANS=BAD_DUMP=0;
- CLASHES=NIL;
- dsetup();
- setprefix(src);
- if(getc(f)!=XVERSION){ BAD_DUMP= -1; return(NIL); }
- if(aliases!=NIL)
- { /* for each `old' install diversion to `new' */
- /* if alias is of form -old `new' is a pname */
- word a,hold;
- ALIASES=aliases;
- for(a=aliases;a!=NIL;a=tl[a])
- { word old=tl[hd[a]],new=hd[hd[a]];
- hold=cons(id_who(old),cons(id_type(old),id_val(old)));
- id_type(old)=alias_t;
- id_val(old)=new;
- if(tag[new]==ID)
- if((id_type(new)!=undef_t||id_val(new)!=UNDEF)
- &&id_type(new)!=alias_t)
- CLASHES=add1(new,CLASHES);
- hd[hd[a]]=hold;
- }
- if(CLASHES!=NIL){ BAD_DUMP= -2; unscramble(aliases); return(NIL); }
- for(a=aliases;a!=NIL;a=tl[a]) /* FIX1 */
- if(tag[ch=id_val(tl[hd[a]])]==ID) /* FIX1 */
- if(id_type(ch)!=alias_t) /* FIX1 */
- id_type(ch)=new_t; /* FIX1 */
- }
- PNBASE=nextpn; /* base for relocation of internal names in dump */
- SUPPRESSED=NIL; /* list of `-id' aliases successfully obeyed */
- TSUPPRESSED=NIL; /* list of -typename aliases (illegal just now) */
- while((ch=getc(f))!=0&&ch!=EOF&&!BAD_DUMP)
- { word s,holde=0;
- dicq=dicp;
- if(files==NIL&&ch==1) /* type error script */
- { holde=getw(f),ch=getc(f);
- if(main)errline=holde; }
- if(ch!='/')(void)strcpy(dicp,prefix),dicq+=preflen;
- /* locate wrt current posn */
- *dicq++ = ch;
- while((*dicq++ =ch=getc(f))&&ch!=EOF); /* filename */
- ovflocheck;
- ch=getw(f); /* mtime */
- s=getc(f); /* share bit */
- /*printf("loading: %s(%d)\n",dicp,ch); /* DEBUG */
- if(files==NIL) /* is this the right dump? */
- if(strcmp(dicp,src))
- { BAD_DUMP=1;
- if(aliases!=NIL)unscramble(aliases);
- return(NIL); }
- CFN=get_id(name()); /* wasteful way to share filename */
- files = cons(make_fil(CFN,ch,s,load_defs(f)),
- files);
- }
-/* warning: load_defs side effects id's in namebuckets, cannot be undone by
-unload until attached to global `files', so interrupts are disabled during
-load_script - see steer.c */ /* for big dumps this may be too coarse - FIX */
- if(ch==EOF||BAD_DUMP){ if(!BAD_DUMP)BAD_DUMP=2;
- if(aliases!=NIL)unscramble(aliases);
- return(files); }
- if(files==NIL){ /* dump of syntax error state */
- extern word oldfiles;
- ch=getw(f);
- if(main)errline=ch;
- while((ch=getc(f))!=EOF)
- { dicq=dicp;
- if(ch!='/')(void)strcpy(dicp,prefix),dicq+=preflen;
- /* locate wrt current posn */
- *dicq++ = ch;
- while((*dicq++ =ch=getc(f))&&ch!=EOF); /* filename */
- ovflocheck;
- ch=getw(f); /* mtime */
- if(oldfiles==NIL) /* is this the right dump? */
- if(strcmp(dicp,src))
- { BAD_DUMP=1;
- if(aliases!=NIL)unscramble(aliases);
- return(NIL); }
- oldfiles = cons(make_fil(get_id(name()),ch,0,NIL),
- oldfiles);
- }
- if(aliases!=NIL)unscramble(aliases);
- return(NIL); }
- algshfns=append1(algshfns,load_defs(f));
- ND=load_defs(f);
- if(ND==True)ND=NIL,TORPHANS=1;
- SGC=append1(SGC,load_defs(f));
- if(main||includees==NIL)freeids=load_defs(f);
- else bindparams(load_defs(f),hdsort(params));
- if(aliases!=NIL)unscramble(aliases);
- if(main)internals=load_defs(f);
- return(reverse(files));
-}/* was it necessary to unscramble aliases before error returns?
- check this later */
-/* actions labelled FIX1 were inserted to deal with the pathological case
- that the destination of an alias (not part of a cyclic alias) has a direct
- definition in the file and the aliasee is missing from the file
- - this is both nameclash and missing aliasee, but without fix the two
- errors cancel each other out and are unreported */
-
-word DETROP=NIL,MISSING=NIL;
-
-bindparams(formal,actual) /* process bindings of free ids */
-/* formal is list of cons(id,cons(original_name,type)) */
-/* actual is list of cons(name,value) | ap(name,typevalue)) */
-/* both in alpha order of original name */
-word formal,actual;
-{ extern word FBS; word badkind=NIL;
- DETROP=MISSING=NIL;
- FBS=cons(formal,FBS);
- /* FBS is list of list of formals bound in current script */
- for(;;)
- { word a; char *f;
- while(formal!=NIL && (actual==NIL ||
- strcmp((f=(char *)hd[hd[tl[hd[formal]]]]),get_id(a=hd[hd[actual]]))<0))
- /* the_val(hd[hd[formal]])=findid((char *)hd[hd[tl[hd[formal]]]]),
- above line picks up identifier of that name in current scope */
- MISSING=cons(hd[tl[hd[formal]]],MISSING),
- formal=tl[formal];
- if(actual==NIL)break;
- if(formal==NIL||strcmp(f,get_id(a)))DETROP=cons(a,DETROP);
- else { word fa=tl[tl[hd[formal]]]==type_t?t_arity(hd[hd[formal]]):-1;
- word ta=tag[hd[actual]]==AP?t_arity(hd[actual]):-1;
- if(fa!=ta)
- badkind=cons(cons(hd[hd[actual]],datapair(fa,ta)),badkind);
- the_val(hd[hd[formal]])=tl[hd[actual]];
- formal=tl[formal]; }
- actual=tl[actual];
- }
-for(;badkind!=NIL;badkind=tl[badkind])
- DETROP=cons(hd[badkind],DETROP);
-}
-
-unscramble(aliases) /* remove old to new diversions installed above */
-word aliases;
-{ word a=NIL;
- for(;aliases!=NIL;aliases=tl[aliases])
- { word old=tl[hd[aliases]],hold=hd[hd[aliases]];
- word new=id_val(old);
- hd[hd[aliases]]=new; /* put back for missing check, see below */
- id_who(old)=hd[hold]; hold=tl[hold];
- id_type(old)=hd[hold];
- id_val(old)=tl[hold]; }
- for(;ALIASES!=NIL;ALIASES=tl[ALIASES])
- { word new=hd[hd[ALIASES]];
- word old=tl[hd[ALIASES]];
- if(tag[new]!=ID)
- { if(!member(SUPPRESSED,new))a=cons(old,a);
- continue; } /* aka stuff irrelevant to pnames */
- if(id_type(new)==new_t)id_type(new)=undef_t; /* FIX1 */
- if(id_type(new)==undef_t)a=cons(old,a); else
- if(!member(CLASHES,new))
- /* install aka info in new */
- if(tag[id_who(new)]!=CONS)
- id_who(new)=cons(datapair(get_id(old),0),id_who(new)); }
- ALIASES=a; /* transmits info about missing aliasees */
-}
-
-char *getaka(x) /* returns original name of x (as a string) */
-word x;
-{ word y=id_who(x);
- return(tag[y]!=CONS?get_id(x):(char *)hd[hd[y]]);
-}
-
-get_here(x) /* here info for id x */
-word x;
-{ word y=id_who(x);
- return(tag[y]==CONS?tl[y]:y);
-}
-
-word *dstack=0,*stackp,*dlim;
-/* stackp=dstack; /* if load_script made interruptible, add to reset */
-
-dsetup()
-{ if(!dstack)
- { dstack=(word *)malloc(1000*sizeof(word));
- if(dstack==NULL)mallocfail("dstack");
- dlim=dstack+1000; }
- stackp=dstack;
-}
-
-dgrow()
-{ word *hold=dstack;
- dstack=(word *)realloc(dstack,2*(dlim-dstack)*sizeof(word));
- if(dstack==NULL)mallocfail("dstack");
- dlim=dstack+2*(dlim-hold);
- stackp += dstack-hold;
- /*printf("dsize=%d\n",dlim-dstack); /* DEBUG */
-}
-
-load_defs(f) /* load a sequence of definitions from file f, terminated
- by DEF_X, or a single object terminated by DEF_X */
-FILE *f;
-{ extern char *dicp, *dicq;
- extern word *pnvec,common_stdin,common_stdinb,nextpn,rv_script;
- word ch,defs=NIL;
- while((ch=getc(f))!=EOF)
- { if(stackp==dlim)dgrow();
- switch(ch)
- { case CHAR_X: *stackp++ = getc(f)+128;
- continue;
- case TVAR_X: *stackp++ = mktvar(getc(f));
- continue;
- case SHORT_X: ch = getc(f);
- if(ch&128)ch= ch|(~127); /*force a sign extension*/
- *stackp++ = stosmallint(ch);
- continue;
- case INT_X: { word *x;
- ch = getw(f);
- *stackp++ = make(INT,ch,0);
- /* for 32 bit version suppress to end of varpart */
- x = &rest(stackp[-1]);
- ch = getw(f);
- while(ch!= -1)
- *x=make(INT,ch,0),ch=getw(f),x= &rest(*x);
- /* end of variable length part */
- continue; }
- case DBL_X: ch=getw(f);
- *stackp++ = make(DOUBLE,ch,getw(f));
- continue;
- case UNICODE_X: *stackp++ = make(UNICODE,getw(f),0);
- continue;
- case PN_X: ch = getc(f);
- ch = PNBASE+(ch|(getc(f)<<8));
- *stackp++ = ch<nextpn?pnvec[ch]:sto_pn(ch);
- /* efficiency hack for *stackp++ = sto_pn(ch); */
- continue;
- case PN1_X: ch=PNBASE+getw(f);
- *stackp++ = ch<nextpn?pnvec[ch]:sto_pn(ch);
- /* efficiency hack for *stackp++ = sto_pn(ch); */
- continue;
- case CONSTRUCT_X: ch = getc(f);
- ch = ch|(getc(f)<<8);
- stackp[-1] = constructor(ch,stackp[-1]);
- continue;
- case RV_X: stackp[-1] = readvals(0,stackp[-1]);
- rv_script=1;
- continue;
- case ID_X: dicq=dicp;
- while((*dicq++ =ch=getc(f))&&ch!=EOF);
- ovflocheck;
- *stackp++=name(); /* see lex.c */
- if(id_type(stackp[-1])==new_t) /* FIX1 (& next 2 lines) */
- CLASHES=add1(stackp[-1],CLASHES),stackp[-1]=NIL;
- else
- if(id_type(stackp[-1])==alias_t) /* follow alias */
- stackp[-1]=id_val(stackp[-1]);
- continue;
- case AKA_X: dicq=dicp;
- while((*dicq++ =ch=getc(f))&&ch!=EOF);
- ovflocheck;
- *stackp++=datapair(get_id(name()),0);
- /* wasteful, to share string */
- continue;
- case HERE_X: dicq=dicp;
- ch=getc(f);
- if(!ch){ /* coding hack, 0 means current file name */
- ch = getc(f);
- ch = ch|getc(f)<<8;
- *stackp++ = fileinfo(CFN,ch);
- continue; }
- /* next line locates wrt current posn */
- if(ch!='/')(void)strcpy(dicp,prefix),dicq+=preflen;
- *dicq++ = ch;
- while((*dicq++ =ch=getc(f))&&ch!=EOF);
- ovflocheck;
- ch = getc(f);
- ch = ch|getc(f)<<8;
- *stackp++ = fileinfo(get_id(name()),ch); /* wasteful */
- continue;
- case DEF_X: switch(stackp-dstack){
- case 0: /* defs delimiter */
- { /*printlist("contents: ",defs); /* DEBUG */
- return(reverse(defs)); }
- case 1: /* ob delimiter */
- { return(*--stackp); }
- case 2: /* pname defn */
- { ch = *--stackp;
- pn_val(ch)= *--stackp;
- defs=cons(ch,defs); /* NB defs now includes pnames */
- continue; }
- case 4:
- if(tag[stackp[-1]]!=ID)
- if(stackp[-1]==NIL){ stackp -= 4; continue; } /* FIX1 */
- else { /* id aliased to pname */
- word akap;
- ch= *--stackp;
- SUPPRESSED=cons(ch,SUPPRESSED);
- stackp--; /* who */
- akap= tag[*stackp]==CONS?hd[*stackp]:NIL;
- stackp--; /* lose type */
- pn_val(ch)= *--stackp;
- if(stackp[1]==type_t&&t_class(ch)!=synonym_t)
- /* suppressed typename */
- { word a=ALIASES; /* reverse assoc in ALIASES */
- while(a!=NIL&&id_val(tl[hd[a]])!=ch)
- a=tl[a];
- if(a!=NIL) /* surely must hold ?? */
- TSUPPRESSED=cons(tl[hd[a]],TSUPPRESSED);
- /*if(akap==NIL)
- akap=datapair(get_id(tl[hd[a]]),0); */
- /*if(t_class(ch)==algebraic_t)
- CSUPPRESS=append1(CSUPPRESS,t_info(ch));
- t_info(ch)= cons(akap,fileinfo(CFN,0));
- /* assists identifn of dangling typerefs
- see privatise() in steer.c */ }else
- if(pn_val(ch)==UNDEF)
- { /* special kludge for undefined names */
- /* necessary only if we allow names specified
- but not defined to be %included */
- if(akap==NIL) /* reverse assoc in ALIASES */
- { word a=ALIASES;
- while(a!=NIL&&id_val(tl[hd[a]])!=ch)
- a=tl[a];
- if(a!=NIL)
- akap=datapair(get_id(tl[hd[a]]),0); }
- pn_val(ch)= ap(akap,fileinfo(CFN,0));
- /* this will generate sensible error message
- see reduction rule for DATAPAIR */
- }
- defs=cons(ch,defs);
- continue; }
- if(
- id_type(stackp[-1])!=new_t&& /* FIX1 */
- (id_type(stackp[-1])!=undef_t||
- id_val(stackp[-1])!=UNDEF)) /* nameclash */
- { if(id_type(stackp[-1])==alias_t) /* cyclic aliasing */
- { word a=ALIASES;
- while(a!=NIL&&tl[hd[a]]!=stackp[-1])a=tl[a];
- if(a==NIL)
- { fprintf(stderr,
- "impossible event in cyclic alias (%s)\n",
- get_id(stackp[-1]));
- stackp-=4;
- continue; }
- defs=cons(*--stackp,defs);
- hd[hd[hd[a]]]= *--stackp; /* who */
- hd[tl[hd[hd[a]]]]= *--stackp; /* type */
- tl[tl[hd[hd[a]]]]= *--stackp; /* value */
- continue; }
- /*if(strcmp(CFN,hd[get_here(stackp[-1])]))
- /* EXPT (ignore clash if from same original file) */
- CLASHES=add1(stackp[-1],CLASHES);
- stackp-=4; }
- else
- defs=cons(*--stackp,defs),
- /*printf("%s undumped\n",get_id(hd[defs])), /* DEBUG */
- id_who(hd[defs])= *--stackp,
- id_type(hd[defs])= *--stackp,
- id_val(hd[defs])= *--stackp;
- continue;
- default:
- { /* printf("badly formed def in dump\n"); /* DEBUG */
- BAD_DUMP=3; return(defs); } /* should unsetids */
- } /* of switch */
- case AP_X: ch = *--stackp;
- if(stackp[-1]==READ&&ch==0)stackp[-1] = common_stdin; else
- if(stackp[-1]==READBIN&&ch==0)stackp[-1] = common_stdinb; else
- stackp[-1] = ap(stackp[-1],ch);
- continue;
- case CONS_X: ch = *--stackp;
- stackp[-1] = cons(ch,stackp[-1]);
- continue;
- default: *stackp++ = ch>127?ch+256:ch;
- }}
- BAD_DUMP=4; /* should unsetids */
- return(defs);
-}
-
-extern char *obsuffix;
-
-okdump(t) /* return 1 if script t has a non-syntax-error dump */
-char *t;
-{ char obf[120];
- FILE *f;
- (void)strcpy(obf,t);
- (void)strcpy(obf+strlen(obf)-1,obsuffix);
- f=fopen(obf,"r");
- if(f&&getc(f)==XVERSION&&getc(f)){fclose(f); return(1); }
- return(0);
-}
-
-geterrlin(t) /* returns errline from dump of t if relevant, 0 otherwise */
-char *t;
-{ char obf[120];
- extern char *dicp,*dicq;
- word ch,el;
- FILE *f;
- (void)strcpy(obf,t);
- (void)strcpy(obf+strlen(obf)-1,obsuffix);
- if(!(f=fopen(obf,"r")))return(0);
- if(getc(f)!=XVERSION||(ch=getc(f))&&ch!=1){ fclose(f);
- return(0); }
- el=getw(f);
- /* now check this is right dump */
- setprefix(t);
- ch=getc(f);
- dicq=dicp;
- if(ch!='/')(void)strcpy(dicp,prefix),dicq+=preflen;
- /* locate wrt current posn */
- *dicq++ = ch;
- while((*dicq++ =ch=getc(f))&&ch!=EOF); /* filename */
- ch=getw(f); /* mtime */
- if(strcmp(dicp,t)||ch!=fm_time(t))return(0); /* wrong dump */
- /* this test not foolproof, strictly should extract all files and check
- their mtimes, as in undump, but this involves reading the whole dump */
- return(el);
-}
-
-hdsort(x) /* sorts list of name-value pairs on name */
-word x;
-{ word a=NIL,b=NIL,hold=NIL;
- if(x==NIL)return(NIL);
- if(tl[x]==NIL)return(x);
- while(x!=NIL) /* split x */
- { hold=a,a=cons(hd[x],b),b=hold;
- x=tl[x]; }
- a=hdsort(a),b=hdsort(b);
- /* now merge two halves back together */
- while(a!=NIL&&b!=NIL)
- if(strcmp(get_id(hd[hd[a]]),get_id(hd[hd[b]]))<0)x=cons(hd[a],x),a=tl[a];
- else x=cons(hd[b],x),b=tl[b];
- if(a==NIL)a=b;
- while(a!=NIL)x=cons(hd[a],x),a=tl[a];
- return(reverse(x));
-}
-#endif
-
-append1(x,y) /* rude append */
-word x,y;
-{ word x1=x;
- if(x1==NIL)return(y);
- while(tl[x1]!=NIL)x1=tl[x1];
- tl[x1]=y;
- return(x);
-}
-
-/* following is stuff for printing heap objects in readable form - used
- for miscellaneous diagnostics etc - main function is out(FILE *,object) */
-
-/* charname returns the printable name of a character, as a string (using
- C conventions for control characters */ /* DAT 13/9/83 */
-/* NB we use DECIMAL (not octal) for miscellaneous unprintables */
-
-/* WARNING - you should take a copy of the name if you intend to do anything
- with it other than print it immediately */
-
-char *charname(c)
-word c;
-{ static char s[5];
- switch(c)
- { case '\n': return("\\n");
- case '\t': return("\\t");
- case '\b': return("\\b");
- case '\f': return("\\f"); /* form feed */
- case '\r': return("\\r"); /* carriage return */
- case '\\': return("\\\\");
- case '\'': return("\\'");
- case '"': return("\\\"");
- /* we escape all quotes for safety, since the context could be either
- character or string quotation */
- default: if(c<32||c>126) /* miscellaneous unprintables -- convert to decimal */
- sprintf(s,"\\%d",c);
- else s[0]=c,s[1]='\0';
- return(s);
- }
-}
-
-out(f,x)
-/* the routines "out","out1","out2" are for printing compiled expressions */
-FILE *f;
-word x;
-{
-#ifdef DEBUG
- static pending=NIL; /* cycle trap */
- word oldpending=pending; /* cycle trap */
-#endif
- if(x<0||x>TOP){ fprintf(f,"<%d>",x); return; }
-#ifdef DEBUG
- if(member(pending,x)){ fprintf(f,"..."); return; } /* cycle trap */
- pending=cons(x,pending); /* cycle trap */
-#endif
- if(tag[x]==LAMBDA)
- { fprintf(f,"$(");out(f,hd[x]);putc(')',f);
- out(f,tl[x]); } else
- { while(tag[x]==CONS)
- { out1(f,hd[x]);
- putc(':',f);
- x= tl[x];
-#ifdef DEBUG
- if(member(pending,x))break; /* cycle trap */
- pending=cons(x,pending); /* cycle trap */
-#endif
- }
- out1(f,x); }
-#ifdef DEBUG
- pending=oldpending; /* cycle trap */
-#endif
-} /* warning - cycle trap not interrupt safe if `out' used in compiling
- process */
-
-out1(f,x)
-FILE *f;
-word x;
-{ if(x<0||x>TOP){ fprintf(f,"<%d>",x); return; }
- if(tag[x]==AP)
- { out1(f,hd[x]);
- putc(' ',f);
- out2(f,tl[x]); }
- else out2(f,x); }
-
-out2(f,x)
-FILE *f;
-word x;
-{ extern char *yysterm[], *cmbnms[];
- if(x<0||x>TOP){ fprintf(f,"<%d>",x); return; }
- if(tag[x]==INT)
- { if(rest(x))
- { x=bigtostr(x);
- while(x)putc(hd[x],f),x=tl[x]; }
- else fprintf(f,"%d",getsmallint(x));
- return; }
- if(tag[x]==DOUBLE){ outr(f,get_dbl(x)); return; }
- if(tag[x]==ID){ fprintf(f,"%s",get_id(x)); return; }
- if(x<256){ fprintf(f,"\'%s\'",charname(x)); return; }
- if(tag[x]==UNICODE){ fprintf(f,"'\%x'",hd[x]); return; }
- if(tag[x]==ATOM)
- { fprintf(f,"%s",x<CMBASE?yysterm[x-256]:
- x==True?"True":
- x==False?"False":
- x==NIL?"[]":
- x==NILS?"\"\"":
- cmbnms[x-CMBASE]);
- return; }
- if(tag[x]==TCONS||tag[x]==PAIR)
- { fprintf(f,"(");
- while(tag[x]==TCONS)
- out(f,hd[x]), putc(',',f), x=tl[x];
- out(f,hd[x]); putc(',',f); out(f,tl[x]);
- putc(')',f); return; }
- if(tag[x]==TRIES)
- { fprintf(f,"TRIES("); out(f,hd[x]); putc(',',f); out(f,tl[x]);
- putc(')',f); return; }
- if(tag[x]==LABEL)
- { fprintf(f,"LABEL("); out(f,hd[x]); putc(',',f); out(f,tl[x]);
- putc(')',f); return; }
- if(tag[x]==SHOW)
- { fprintf(f,"SHOW("); out(f,hd[x]); putc(',',f); out(f,tl[x]);
- putc(')',f); return; }
- if(tag[x]==STARTREADVALS)
- { fprintf(f,"READVALS("); out(f,hd[x]); putc(',',f); out(f,tl[x]);
- putc(')',f); return; }
- if(tag[x]==LET)
- { fprintf(f,"(LET ");
- out(f,dlhs(hd[x])),fprintf(f,"=");
- out(f,dval(hd[x])),fprintf(f,";IN ");
- out(f,tl[x]);
- fprintf(f,")"); return; }
- if(tag[x]==LETREC)
- { word body=tl[x];
- fprintf(f,"(LETREC ");
- x=hd[x];
- while(x!=NIL)out(f,dlhs(hd[x])),fprintf(f,"="),
- out(f,dval(hd[x])),fprintf(f,";"),x=tl[x];
- fprintf(f,"IN ");
- out(f,body);
- fprintf(f,")"); return; }
- if(tag[x]==DATAPAIR)
- { fprintf(f,"DATAPAIR(%s,%d)",(char *)hd[x],tl[x]);
- return; }
- if(tag[x]==FILEINFO)
- { fprintf(f,"FILEINFO(%s,%d)",(char *)hd[x],tl[x]);
- return; }
- if(tag[x]==CONSTRUCTOR)
- { fprintf(f,"CONSTRUCTOR(%d)",hd[x]);
- return; }
- if(tag[x]==STRCONS)
- { fprintf(f,"<$%d>",hd[x]); return; }/* used as private id's, inter alia*/
- if(tag[x]==SHARE)
- { fprintf(f,"(SHARE:"); out(f,hd[x]); fprintf(f,")"); return; }
- if(tag[x]!=CONS&&tag[x]!=AP&&tag[x]!=LAMBDA)
- /* not a recognised structure */
- { fprintf(f,"<%d|tag=%d>",x,tag[x]); return; }
- putc('(',f);
- out(f,x);
- putc(')',f); }
-
-outr(f,r) /* prints a number */
-FILE *f;
-double r;
-{ double p;
- p= r<0?-r: r;
- if(p>=1000.0||p<=.001)fprintf(f,"%e",r);
- else fprintf(f,"%f",r); }
-
-/* end of MIRANDA DATA REPRESENTATIONS */
-
diff --git a/new/lex.c b/new/lex.c
deleted file mode 100644
index a4e9d09..0000000
--- a/new/lex.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-/* MIRANDA LEX ANALYSER */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-#include "data.h"
-#include "lex.h"
-#include <errno.h>
-
-extern word DICSPACE; /* see steer.c for default value */
-/* capacity in chars of dictionary space for storing identifiers and file names
- to get a larger name space just increase this number */
-extern FILE *s_in;
-extern word echoing,listing,verbosity,magic,inbnf,inlex;
-word fileq=NIL; /* list of currently open-for-input files, of form
- cons(strcons(stream,<ptr to element of 'files'>),...)*/
-word insertdepth= -1,margstack=NIL,col=0,lmargin=0;
-word echostack=NIL;
-word lverge=0,vergstack=NIL;
-char *prefixbase; /* stores prefixes for pathnames, to get static resolution */
-word prefixlimit=1024; /* initial size of space for prefixes */
-word prefix,prefixstack=NIL; /* current prefix, stack of old prefixes */
-word atnl=1,line_no=0;
-word lastline;
-word litstack=NIL,linostack=NIL;
-word c=' ', lastc;
-word commandmode;
-word common_stdin,common_stdinb,cook_stdin;
-word litmain=0,literate=0; /* flags "literate" comment convention */
-char *dic,*dicp,*dicq;
-char *pathname();
-
-setupdic()
-{ dicp=dicq=dic=malloc(DICSPACE);
- if(dic==NULL)mallocfail("dictionary");
- /* it is not permissible to realloc dic, because at the moment identifiers
- etc. contain absolute pointers into the dictionary space - so we must
- choose fairly large initial value for DICSPACE. Fix this later */
- prefixbase=malloc(prefixlimit);
- prefixbase[0]='\0';
- prefix=0;
-}
-
-/* this allows ~login convention in filenames */
-/* #define okgetpwnam
-/* suppress 26.5.06 getpwnam cases runtime error when statically linked (Linux) */
-
-#ifdef okgetpwnam
-#include <pwd.h>
-struct passwd *getpwnam();
-#endif
-char *getenv();
-
-char *gethome(n) /* for expanding leading `~' in tokens and pathnames */
-char *n;
-{ struct passwd *pw;
- if(n[0]=='\0')return(getenv("HOME"));
-#ifdef okgetpwnam
- if(pw=getpwnam(n))return(pw->pw_dir);
-#endif
- return(NULL);
-}
-
-#define ovflocheck if(dicq-dic>DICSPACE)dicovflo()
-
-dicovflo() /* is this called everywhere it should be? Check later */
-{ fprintf(stderr,"\npanic: dictionary overflow\n"); exit(1); }
-
-char *token() /* lex analyser for command language (very simple) */
-{ extern char *current_script;
- word ch=getchar();
- dicq = dicp; /* uses top of dictionary as temporary work space */
- while(ch==' '||ch=='\t')ch=getchar();
- if(ch=='~')
- { char *h;
- *dicq++ = ch;
- ch=getchar();
- while(isalnum(ch)||ch=='-'||ch=='_'||ch=='.')
- *dicq++ = ch,ch=getchar();
- /* NB csh does not allow `.' in user ids when expanding `~'
- but this may be a mistake */
- *dicq='\0';
- if(h=gethome(dicp+1))
- (void)strcpy(dicp,h),dicq=dicp+strlen(dicp);
- }
-#ifdef SPACEINFILENAMES
- if(ch!='"'&&ch!='<') /* test added 9.5.06 see else part */
-#endif
- while(!isspace(ch)&&ch!=EOF)
- { *dicq++ = ch;
- if(ch=='%')
- if(dicq[-2]=='\\')(--dicq)[-1]='%';
- else dicq--,(void)strcpy(dicq,current_script),dicq+=strlen(dicq);
- ch=getchar(); }
-#ifdef SPACEINFILENAMES
- else { word closeq= ch=='<'?'>':'"'; /* this branch added 9.5.06 */
- *dicq++ = ch; /* to allow spaces in "tok" or <tok> */
- ch=getchar();
- while(ch!=closeq&&ch!='\n'&&ch!=EOF)
- *dicq++ = ch, ch=getchar();
- if(ch==closeq)*dicq++ = ch, ch=getchar(); }
-#endif
- *dicq++ = '\0';
- ovflocheck;
- while(ch==' '||ch=='\t')ch=getchar();
- ungetc(ch,stdin);
- return(*dicp=='\0'?(char *)NULL:dicp);
-} /* NB - if no token returns NULL rather than pointer to empty string */
-
-char *addextn(b,s) /* if(b)force s to end in ".m", and resolve <quotes> */
-word b;
-char *s;
-{ extern char *miralib;
- extern char linebuf[];
- word n=strlen(s);
- /* printf("addextn(%s)\n",s); /* DEBUG */
- if(s[0]=='<'&&s[n-1]=='>')
- { static miralen=0; /* code to handle quotes added 21/1/87 */
- if(!miralen)miralen=strlen(miralib);
- strcpy(linebuf,miralib);
- linebuf[miralen]= '/';
- strcpy(linebuf+miralen+1,s+1);
- strcpy(dicp,linebuf);
- s=dicp;
- n=n+miralen-1;
- dicq=dicp+n+1;
- dicq[-1] = '\0'; /* overwrites '>' */
- ovflocheck; } else
- if(s[0]=='\"'&&s[n-1]=='\"')
- { /*strip quotes */
- dicq=dicp; s++;
- while(*s)*dicq++ = *s++;
- dicq[-1]='\0'; /* overwrites '"' */
- s=dicp; n=n-2;
- }
- if(!b||strcmp(s+n-2,".m")==0)return(s);
- if(s==dicp)dicq--;/*if s in scratch area at top of dic, extend in situ*/
- else { /* otherwise build new copy at top of dic */
- dicq=dicp;
- while(*s)*dicq++ = *s++;
- *dicq = '\0'; }
- if(strcmp(dicq-2,".x")==0)dicq -= 2; else
- if(dicq[-1]=='.')dicq -= 1;
- (void)strcpy(dicq,".m");
- dicq += 3;
- ovflocheck;
- /* printf("return(%s)\n",dicp); /* DEBUG */
- return(dicp);
-} /* NB - call keep(dicp) if the result is to be retained */
-
-word brct=0;
-
-spaces(n)
-word n;
-{ while(n-- >0)putchar(' ');
-}
-
-litname(s)
-char *s;
-{ word n=strlen(s);
- return(n>=6 && strcmp(s+n-6,".lit.m")==0);
-}
-
-word getch() /* keeps track of current position in the variable "col"(column) */
-{ word ch= getc(s_in);
- if(ch==EOF&&!atnl&&tl[fileq]==NIL) /* badly terminated top level file */
- { atnl=1; return('\n'); }
- if(atnl)
- { if((line_no==0&&!commandmode||magic&&line_no==1)&&litstack==NIL)
- litmain=literate= (ch=='>')||litname(get_fil(current_file));
- if(literate)
- { word i=0;
- while(ch!=EOF&&ch!='>')
- { ungetc(ch,s_in);
- line_no++;
- (void)fgets(dicp,250,s_in);
- if(i==0&&line_no>1)chblank(dicp); i++;
- if(echoing)spaces(lverge),fputs(dicp,stdout);
- ch=getc(s_in); }
- if((i>1||line_no==1&&i==1)&&ch!=EOF)chblank(dicp);
- if(ch=='>')
- { if(echoing)putchar(ch),spaces(lverge);ch=getc(s_in); }
- } /* supports alternative `literate' comment convention */
- atnl=0; col= lverge+literate;
- if(!commandmode&&ch!=EOF)line_no++; }
- if(echoing&&ch!=EOF)
- { putchar(ch);
- if(ch=='\n'&&!literate)
- if(litmain)putchar('>'),spaces(lverge);
- else spaces(lverge);
- }
- if(ch=='\t')col= ((col-lverge)/8 + 1)*8+lverge;
- else col++;
- if(ch=='\n')atnl= 1;
- return(ch); }
-
-word blankerr=0;
-
-chblank(s)
-char *s;
-{ while(*s==' '||*s=='\t')s++;
- if(*s=='\n')return;
- syntax("formal text not delimited by blank line\n");
- blankerr=1;
- reset(); /* easiest way to recover is to pretend it was an interrupt */
-}
-
-/* getlitch gets a character from input like getch, but using C escaping
- conventions if the char is backslash -- for use in reading character
- and string constants */
-
-word rawch;
-/* it is often important to know, when certain characters are returned (e.g.
- quotes and newlines) whether they were escaped or literal */
-
-word errch; /* for reporting unrecognised \escape */
-
-word getlitch()
-{ extern word UTF8;
- word ch=c;
- rawch = ch;
- if(ch=='\n')return(ch); /* always an error */
- if(UTF8&&ch>127)
- { /* UTF-8 uses 2 or 3 bytes for unicode points to 0xffff */
- word ch1=c=getch();
- if((ch&0xe0)==0xc0) /* 2 bytes */
- { if((ch1&0xc0)!=0x80)
- return -5; /* not valid UTF8 */
- c=getch();
- return sto_char((ch&0x1f)<<6|ch1&0x3f); }
- word ch2=c=getch();
- if((ch&0xf0)==0xe0) /* 3 bytes */
- { if((ch1&0xc0)!=0x80||(ch2&0xc0)!=0x80)
- return -5; /* not valid UTF8 */
- c=getch();
- return sto_char((ch&0xf)<<12|(ch1&0x3f)<<6|ch2&0x3f); }
- word ch3=c=getch();
- if((ch&0xf8)==0xf0) /* 4 bytes, beyond basic multiligual plane */
- { if((ch1&0xc0)!=0x80||(ch2&0xc0)!=0x80||(ch3&0xc0)!=0x80)
- return -5; /* not valid UTF8 */
- c=getch();
- return((ch&7)<<18|(ch1&0x3f)<<12|(ch2&0x3f)<<6|ch3&0x3f); }
- return(-5);
- /* not UTF8 */
- }
- if(ch!='\\')
- { c=getch(); return(ch); }
- ch = getch();
- c = getch();
- switch(ch)
- { case '\n': return(getlitch()); /* escaped nl was handled in 'getch()' */
- case 'a': return('\a');
- case 'b': return('\b');
- case 'f': return('\f'); /* form feed */
- case 'n': return('\n'); /* newline, == linefeed */
- case 'r': return('\r'); /* carriage return */
- case 't': return('\t');
- case 'v': return('\v');
- case 'X': /* omit for Haskell escape rules, see also lines marked H */
- case 'x': if(isxdigit(c))
- { word value, N=ch=='x'?4:6; /* N=7 for Haskell escape rules */
- char hold[8];
- ch = c;
- word count=0;
- /* while(ch=='0'&&isxdigit(peekch()))ch=getch(); /* H-lose leading 0s */
- while(isxdigit(ch)&&count<N)
- hold[count++]=ch,ch=getch();
- /* read upto N hex digits */
- hold[count] = '\0';
- sscanf(hold,"%x",&value);
- c = ch;
- return value>UMAX?-3 /* \x out of range */
- :sto_char(value); }
- else return -2; /* \x with no hex digits */
- default: if('0'<=ch&&ch<='9')
- { word n=ch-'0',count=1,N=3; /* N=8 for Haskell escape rules */
- ch = c;
- /* while(ch=='0'&&isdigit(peekch()))ch=getch(); /* H-lose leading 0s */
- while(isdigit(ch)&&count<N)
- /* read upto N digits */
- { n = 10*n+ch-'0';
- count++;
- ch = getch(); }
- c = ch;
- return /* n>UMAX?-4: /* H \decimal out of range */
- sto_char(n); }
- if(ch=='\''||ch=='"'||ch=='\\'||ch=='`')return(ch); /* see note */
- if(ch=='&')return -7; /* Haskell null escape, accept silently */
- errch=ch<=255?ch:'?';
- return -6; /* unrecognised \something */
- }
-} /* note: we accept \` for ` because getlitch() is used by charclass() */
-
-char *rdline() /* used by the "!" command -- see RULES */
-{ extern char *current_script;
- static char linebuf[BUFSIZE];
- char *p=linebuf;
- word ch=getchar(),expansion=0;
- while(ch==' '||ch=='\t')ch=getchar();
- if(ch=='\n'||ch=='!'&&!(*linebuf))
- { /* "!!" or "!" on its own means repeat last !command */
- if(*linebuf)printf("!%s",linebuf);
- while(ch!='\n'&&ch!=EOF)ch=getchar();
- return(linebuf); }
- if(ch=='!')
- expansion=1,p=linebuf+strlen(linebuf)-1; /* p now points at old '\n' */
- else ungetc(ch,stdin);
- while((*p++ =ch=getchar())!='\n'&&ch!=EOF)
- if(p-linebuf>=BUFSIZE)
- { *p='\0';
- fprintf(stderr,"sorry, !command too long (limit=%d chars): %s...\n",
- BUFSIZE,linebuf);
- while((ch=getchar())!='\n'&&ch!=EOF);
- return(NULL);
- } else
- if(p[-1]=='%')
- if(p>linebuf+1&&p[-2]=='\\')(--p)[-1]='%'; else
- { (void)strncpy(p-1,current_script,linebuf+BUFSIZE-p);
- p = linebuf+strlen(linebuf);
- expansion = 1;
- }
- *p = '\0';
- if(expansion)printf("!%s",linebuf);
- return(linebuf); }
-
-setlmargin() /* this and the next routine are used to enforce the offside
- rule ("yylex" refuses to read a symbol if col<lmargin) */
-{ margstack= cons(lmargin,margstack);
- if(lmargin<col)lmargin= col; } /* inner scope region cannot "protrude" */
-
-unsetlmargin()
-{ if(margstack==NIL)return; /* in case called after `syntax("..")' */
- lmargin= hd[margstack];
- margstack= tl[margstack]; }
-
-word okid();
-word okulid();
-word PREL=1;
-
-#define isletter(c) ('a'<=c&&c<='z'||'A'<=c&&c<='Z')
-
-errclass(word val, word string)
-/* diagnose error in charclass, string or char const */
-{ char *s = string==2?"char class":string?"string":"char const";
- if(val==-2)printf("\\x with no xdigits in %s\n",s); else
- if(val==-3)printf("\\hexadecimal escape out of range in %s\n",s); else
- if(val==-4)printf("\\decimal escape out of range in %s\n",s); else
- if(val==-5)printf("unrecognised character in %s"
- "(UTF8 error)\n",s); else
- if(val==-6)printf("unrecognised escape \\%c in %s\n",errch,s); else
- if(val==-7)printf("illegal use of \\& in char const\n"); else
- printf("unknown error in %s\n",s);
- acterror(); }
-
-yylex() /* called by YACC to get the next symbol */
-{ extern word SYNERR,exportfiles,inexplist,sreds;
- /* SYNERR flags context sensitive syntax error detected in actions */
- if(SYNERR)return(END); /* tell YACC to go home */
- layout();
- if(c=='\n') /* can only occur in command mode */
-/* if(magic){ commandmode=0; /* expression just read, now script */
-/* line_no=2;
-/* return(c); } else /* no longer relevant 26.11.2019 */
- return(END);
- if(col<lmargin)
- if(c=='='&&(margstack==NIL||col>=hd[margstack]))/* && part fixes utah.bug*/
- { c = getch();
- return(ELSEQ); /* ELSEQ means "OFFSIDE =" */
- }
- else return(OFFSIDE);
- if(c==';') /* fixes utah2.bug */
- { c=getch(); layout();
- if(c=='='&&(margstack==NIL||col>=hd[margstack]))
- { c = getch();
- return(ELSEQ); /* ELSEQ means "OFFSIDE =" */
- }
- else return(';');
- }
- if(
- /* c=='_'&&okid(peekch()) || /* _id/_ID as lowercase id */
- isletter(c)){ kollect(okid);
- if(inlex==1){ layout();
- yylval=name();
- return(c=='='?LEXDEF:
- isconstructor(yylval)?CNAME:
- NAME); }
- if(inbnf==1)
- /* add trailing space to nonterminal to avoid clash
- with ordinary names */
- dicq[-1] = ' ',
- *dicq++ = '\0';
- return(identifier(0)); }
- if('0'<=c&&c<='9'||c=='.'&&peekdig())
- { if(c=='0'&&tolower(peekch())=='x')
- hexnumeral(); else /* added 21.11.2013 */
- if(c=='0'&&tolower(peekch())=='o')
- getch(),c=getch(),octnumeral(); /* added 21.11.2013 */
- else numeral();
- return(CONST); }
- if(c=='%'&&!commandmode)return(directive());
- if(c=='\'')
- { c = getch();
- yylval= getlitch();
- if(yylval<0){ errclass(yylval,0); return CONST; }
- if(!is_char(yylval))
- printf("%simpossible event while reading char const ('\\%u\')\n",
- echoing?"\n":"",yylval),
- acterror();
- if(rawch=='\n'||c!='\'')syntax("improperly terminated char const\n");
- else c= getch();
- return(CONST); }
- if(inexplist&&(c=='\"'||c=='<'))
- { if(!pathname())syntax("badly formed pathname in %export list\n");
- else exportfiles=strcons(addextn(1,dicp),exportfiles),
- keep(dicp);
- return(PATHNAME); }
- if(inlex==1&&c=='`')
- { return(charclass()?ANTICHARCLASS:CHARCLASS); }
- if(c=='\"')
- { string();
- if(yylval==NIL)yylval=NILS; /* to help typechecker! */
- return(CONST); }
- if(inbnf==2) /* fiddle to offside rule in grammars */
- if(c=='[')brct++; else if(c==']')brct--; else
- if(c=='|'&&brct==0)
- return(OFFSIDE);
- if(c==EOF)
- { if(tl[fileq]==NIL&&margstack!=NIL)return(OFFSIDE); /* to fix dtbug */
- fclose((FILE *)hd[hd[fileq]]);
- fileq= tl[fileq]; insertdepth--;
- if(fileq!=NIL&&hd[echostack])
- { if(literate)putchar('>'),spaces(lverge);
- printf("<end of insert>"); }
- s_in= fileq==NIL?stdin:(FILE *)hd[hd[fileq]];
- c= ' ';
- if(fileq==NIL)
- { lverge=c=col=lmargin=0;
- /* c=0; necessary because YACC sometimes reads 1 token past END */
- atnl=1;
- echoing=verbosity&listing;
- lastline=line_no;
- /* hack so errline can be set right if err at end of file */
- line_no=0;
- litmain=literate=0;
- return(END); }
- else { current_file = tl[hd[fileq]];
- prefix=hd[prefixstack];
- prefixstack=tl[prefixstack];
- echoing=hd[echostack];
- echostack=tl[echostack];
- lverge=hd[vergstack];
- vergstack=tl[vergstack];
- literate=hd[litstack];
- litstack=tl[litstack];
- line_no=hd[linostack];
- linostack=tl[linostack]; }
- return(yylex()); }
- lastc= c;
- c= getch();
-#define try(x,y) if(c==x){ c=getch(); return(y); }
- switch(lastc) {
- case '_': if(c=='') /* underlined something */
- { c=getch();
- if(c=='<'){ c=getch(); return(LE); }
- if(c=='>'){ c=getch(); return(GE); }
- if(c=='%'&&!commandmode)return(directive());
- if(isletter(c)) /* underlined reserved word */
- { kollect(okulid);
- if(dicp[1]=='_'&&dicp[2]=='')
- return(identifier(1)); }
- syntax("illegal use of underlining\n");
- return('_'); }
- return(lastc);
- case '-': try('>',ARROW) try('-',MINUSMINUS) return(lastc);
- case '<': try('-',LEFTARROW) try('=',LE) return(lastc);
- case '=': if(c=='>'){ syntax("unexpected symbol =>\n"); return '='; }
- try('=',EQEQ) return(lastc);
- case '+': try('+',PLUSPLUS) return(lastc);
- case '.': if(c=='.')
- { c=getch();
- return(DOTDOT);
- }
- return(lastc);
- case '\\': try('/',VEL) return(lastc);
- case '>': try('=',GE) return(lastc);
- case '~': try('=',NE) return(lastc);
- case '&': if(c=='>')
- { c=getch();
- if(c=='>')yylval=1;
- else yylval=0,ungetc(c,s_in);
- c=' ';
- return(TO); }
- return(lastc);
- case '/': try('/',DIAG) return(lastc);
- case '*': try('*',collectstars()) return(lastc);
- case ':': if(c==':')
- { c=getch();
- if(c=='='){ c=getch(); return(COLON2EQ); }
- else return(COLONCOLON);
- }
- return(lastc);
- case '$': if(
- /* c=='_'&&okid(peekch())|| /* _id/_ID as id */
- isletter(c))
- { word t;
- kollect(okid);
- t=identifier(0);
- return(t==NAME?INFIXNAME:t==CNAME?INFIXCNAME:'$'); }
- /* the last alternative is an error - caveat */
- if('1'<=c&&c<='9')
- { word n=0;
- while(isdigit(c)&&n<1e6)n=10*n+c-'0',c=getch();
- if(n>sreds)
- /* sreds==0 everywhere except in semantic redn clause */
- printf("%ssyntax error: illegal symbol $%d%s\n",
- echoing?"\n":"",n,n>=1e6?"...":""),
- acterror();
- else { yylval=mkgvar(n); return(NAME); }
- }
- if(c=='-')
- { if(!compiling)
- syntax("unexpected symbol $-\n"); else
- {c=getch(); yylval=common_stdin; return(CONST); }}
- /* NB we disallow recursive use of $($/+/-) inside $+ data
- whence addition of `compiling' to premises */
- if(c==':')
- { c=getch();
- if(c!='-')syntax("unexpected symbol $:\n"); else
- { if(!compiling)
- syntax("unexpected symbol $:-\n"); else
- {c=getch(); yylval=common_stdinb; return(CONST); }}} /* $:- */
- if(c=='+')
- { /* if(!(commandmode&&compiling||magic))
- syntax("unexpected symbol $+\n"); else /* disallow in scripts */
- if(!compiling)
- syntax("unexpected symbol $+\n"); else
- { c=getch();
- if(commandmode)
- yylval=cook_stdin;
- else yylval=ap(readvals(0,0),OFFSIDE);
- return(CONST); }}
- if(c=='$')
- { if(!(inlex==2||commandmode&&compiling))
- syntax("unexpected symbol $$\n"); else
- { c=getch();
- if(inlex) { yylval=mklexvar(0); return(NAME); }
- else return(DOLLAR2); }}
- if(c=='#')
- { if(inlex!=2)syntax("unexpected symbol $#\n"); else
- { c=getch(); yylval=mklexvar(1); return(NAME); }}
- if(c=='*')
- { c=getch(); yylval=ap(GETARGS,0); return(CONST); }
- if(c=='0')
- syntax("illegal symbol $0\n");
- default: return(lastc);
-}}
-
-layout()
-{L:while(c==' '||c=='\n'&&!commandmode||c=='\t') c= getch();
- if(c==EOF&&commandmode){ c='\n'; return; }
- if(c=='|'&&peekch()=='|' /* ||comments */
- || col==1&&line_no==1 /* added 19.11.2013 */
- &&c=='#'&&peekch()=='!') /* UNIX magic string */
- { while((c=getch())!='\n'&&c!=EOF);
- if(c==EOF&&!commandmode)return;
- c= '\n';
- goto L; }
-}
-
-collectstars()
-{ word n=2;
- while(c=='*')c=getch(),n++;
- yylval= mktvar(n);
- return(TYPEVAR);
-}
-
-word gvars=NIL; /* list of grammar variables - no need to reset */
-
-mkgvar(i) /* make bound variable (corresponding to $i in bnf rule) */
-word i;
-{ word *p= &gvars;
- while(--i)
- { if(*p==NIL)*p=cons(sto_id("gvar"),NIL);
- p= &tl[*p]; }
- if(*p==NIL)*p=cons(sto_id("gvar"),NIL);
- return(hd[*p]);
-} /* all these variables have the same name, and are not in hashbucket */
-
-word lexvar=0;
-
-mklexvar(i) /* similar - corresponds to $$, $# on rhs of %lex rule */
-word i; /* i=0 or 1 */
-{ extern word ltchar;
- if(!lexvar)
- lexvar=cons(sto_id("lexvar"),sto_id("lexvar")),
- id_type(hd[lexvar])=ltchar,
- id_type(tl[lexvar])=genlstat_t();
- return(i?tl[lexvar]:hd[lexvar]);
-}
-
-word ARGC;
-char **ARGV; /* initialised in main(), see steer.c */
-
-conv_args() /* used to give access to command line args
- see case GETARGS in reduce.c */
-{ word i=ARGC,x=NIL;
- if(i==0)return(NIL); /* possible only if not invoked from a magic script */
- { while(--i)x=cons(str_conv(ARGV[i]),x);
- x=cons(str_conv(ARGV[0]),x); }
- return(x);
-}
-
-str_conv(s) /* convert C string to Miranda form */
-char *s;
-{ word x=NIL,i=strlen(s);
- while(i--)x=cons(s[i],x);
- return(x);
-} /* opposite of getstring() - see reduce.c */
-
-okpath(ch)
-word ch;
-{ return(ch!='\"'&&ch!='\n'&&ch!='>'); }
-
-char *pathname() /* returns NULL if not valid pathname (in string quotes) */
-{ layout();
- if(c=='<') /* alternative quotes <..> for system libraries */
- { extern char *miralib;
- char *hold=dicp;
- c=getch();
- (void)strcpy(dicp,miralib);
- dicp+=strlen(miralib);
- *dicp++ = '/';
- kollect(okpath);
- dicp=hold;
- if(c!='>')return(NULL);
- c=' ';
- return(dicp); }
- if(c!='\"')return(NULL);
- c=getch();
- if(c=='~')
- { char *h,*hold=dicp;
- extern char linebuf[];
- *dicp++ = c;
- c=getch();
- while(isalnum(c)||c=='-'||c=='_'||c=='.')
- *dicp++ = c, c=getch();
- *dicp='\0';
- if(h=gethome(hold+1))
- (void)strcpy(hold,h),dicp=hold+strlen(hold);
- else (void)strcpy(&linebuf[0],hold),
- (void)strcpy(hold,prefixbase+prefix),
- dicp=hold+strlen(prefixbase+prefix),
- (void)strcpy(dicp,&linebuf[0]),
- dicp+=strlen(dicp);
- kollect(okpath);
- dicp=hold;
- } else
- if(c=='/') /* absolute pathname */
- kollect(okpath);
- else { /* relative pathname */
- char *hold=dicp;
- (void)strcpy(dicp,prefixbase+prefix);
- dicp+=strlen(prefixbase+prefix);
- kollect(okpath);
- dicp=hold; }
- if(c!='\"')return(NULL);
- c = ' ';
- return(dicp);
-} /* result is volatile - call keep(dicp) to retain */
-
-adjust_prefix(f) /* called at %insert and at loadfile, to get static pathname
- resolution */
-char *f;
-{ /* the directory part of the pathname f becomes the new
- prefix for pathnames, and we stack the current prefix */
- char *g;
- prefixstack=strcons(prefix,prefixstack);
- prefix += strlen(prefixbase+prefix)+1;
- while(prefix+strlen(f)>=prefixlimit) /* check and fix overflow */
- prefixlimit += 1024, prefixbase=realloc(prefixbase,prefixlimit);
- (void)strcpy(prefixbase+prefix,f);
- g=rindex(prefixbase+prefix,'/');
- if(g)g[1]='\0';
- else prefixbase[prefix]='\0';
-}
-
-/* NOTES on how static pathname resolution is achieved:
-(the specification is that pathnames must always be resolved relative to the
-file in which they are encountered)
-Definition -- the 'prefix' of a pathname is the initial segment up to but not
-including the last occurrence of '/' (null if no '/' present).
-Keep the wd constant during compilation. Have a global char* prefix, initially
-null.
-1) Whenever you read a relative pathname(), insert 'prefix' on the front of it.
-2) On entering a new level of insert, stack old prefix and prefix becomes that
- of new file name. Done by calling adjust_prefix().
-3) On quitting a level of insert, unstack old prefix.
-*/
-
-peekdig()
-{ word ch = getc(s_in);
- ungetc(ch,s_in);
- return('0'<=ch&&ch<='9');
-}
-
-peekch()
-{ word ch = getc(s_in);
- ungetc(ch,s_in);
- return(ch);
-}
-
-openfile(n) /* returns 0 or 1 as indication of success - puts file on fileq
- if successful */
-char *n;
-{ FILE *f;
- f= fopen(n,"r");
- if(f==NULL)return(0);
- fileq= cons(strcons(f,NIL),fileq);
- insertdepth++;
- return(1);
-}
-
-identifier(s) /* recognises reserved words */
-word s; /* flags looking for ul reserved words only */
-{ extern word lastid,initialising;
- if(inbnf==1)
- { /* only reserved nonterminals are `empty', `end', `error', `where' */
- if(is("empty ")||is("e_m_p_t_y"))return(EMPTYSY); else
- if(is("end ")||is("e_n_d"))return(ENDSY); else
- if(is("error ")||is("e_r_r_o_r"))return(ERRORSY); else
- if(is("where ")||is("w_h_e_r_e"))return(WHERE); }
- else
- switch(dicp[0])
- { case 'a': if(is("abstype")||is("a_b_s_t_y_p_e"))
- return(ABSTYPE);
- break;
- case 'd': if(is("div")||is("d_i_v"))
- return(DIV);
- break;
- case 'F': if(is("False")) /* True, False alleged to be predefined, not
- reserved (??) */
- { yylval = False;
- return(CONST); }
- break;
- case 'i': if(is("if")||is("i_f"))
- return(IF);
- break;
- case 'm': if(is("mod")||is("m_o_d"))
- return(REM);
- break;
- case 'o': if(is("otherwise")||is("o_t_h_e_r_w_i_s_e"))
- return(OTHERWISE);
- break;
- case 'r': if(is("readvals")||is("r_e_a_d_v_a_l_s"))
- return(READVALSY);
- break;
- case 's': if(is("show")||is("s_h_o_w"))
- return(SHOWSYM);
- break;
- case 'T': if(is("True"))
- { yylval = True;
- return(CONST); }
- case 't': if(is("type")||is("t_y_p_e"))
- return(TYPE);
- break;
- case 'w': if(is("where")||is("w_h_e_r_e"))
- return(WHERE);
- if(is("with")||is("w_i_t_h"))
- return(WITH);
- break;
- }
- if(s){ syntax("illegal use of underlining\n"); return('_'); }
- yylval=name(); /* not a reserved word */
- if(commandmode&&lastid==0&&id_type(yylval)!=undef_t)lastid=yylval;
- return(isconstructor(yylval)?CNAME:NAME);
-}
-
-word disgusting=0; /* flag to turn off typecheck, temporary hack for jrc */
-
-directive() /* these are of the form "%identifier" */
-{ extern word SYNERR,magic;
- word holdcol=col-1,holdlin=line_no;
- c = getch();
- if(c=='%'){ c=getch(); return(ENDIR); }
- kollect(okulid);
- switch(dicp[0]=='_'&&dicp[1]==''?dicp[2]:dicp[0])
- { case 'b': if(is("begin")||is("_^Hb_^He_^Hg_^Hi_^Hn"))
- if(inlex)
- return(LBEGIN);
- if(is("bnf")||is("_^Hb_^Hn_^Hf"))
- { setlmargin(); col=holdcol+4;
- /* `indent' to right hand end of directive */
- return(BNF); }
- break;
- case 'e': if(is("export")||is("_e_x_p_o_r_t"))
- { if(magic)syntax(
- "%export directive not permitted in \"-exp\" script\n");
- return(EXPORT); }
- break;
- case 'f': if(is("free")||is("_f_r_e_e"))
- { if(magic)syntax(
- "%free directive not permitted in \"-exp\" script\n");
- return(FREE); }
- break;
- case 'i': if(is("include")||is("_i_n_c_l_u_d_e"))
- { if(!SYNERR){ layout(); setlmargin(); }
- /* does `indent' for grammar */
- if(!pathname())
- syntax("bad pathname after %include\n");
- else yylval=strcons(addextn(1,dicp),
- fileinfo(get_fil(current_file),holdlin)),
- /* (includee,hereinfo) */
- keep(dicp);
- return(INCLUDE); }
- if(is("insert")||is("_i_n_s_e_r_t"))
- { char *f=pathname();
- if(!f)syntax("bad pathname after %insert\n"); else
- if(insertdepth<12&&openfile(f))
- { adjust_prefix(f);
- vergstack=cons(lverge,vergstack);
- echostack=cons(echoing,echostack);
- litstack=cons(literate,litstack);
- linostack=strcons(line_no,linostack);
- line_no=0; atnl=1; /* was line_no=1; */
- keep(dicp);
- current_file = make_fil(f,fm_time(f),0,NIL);
- files = append1(files,cons(current_file,NIL));
- tl[hd[fileq]] = current_file;
- s_in = (FILE *)hd[hd[fileq]];
- literate= peekch()=='>'||litname(f);
- col=lverge=holdcol;
- if(echoing)
- { putchar('\n');
- if(!literate)
- if(litmain)putchar('>'),spaces(holdcol);
- else spaces(holdcol); }
- c = getch(); } /* used to precede previous cmd when echo
- was delayed by one char, see getch() */
- else { word toomany=(insertdepth>=12);
- printf("%s%%insert error - cannot open \"%s\"\n",
- echoing?"\n":"",f);
- keep(dicp);
- if(toomany)printf(
- "too many nested %%insert directives (limit=%d)\n",
- insertdepth);
- else
- files = append1(files,cons(make_fil(f,0,0,NIL),NIL));
- /* line above for benefit of `oldfiles' */
- acterror(); }
- return(yylex()); }
- break;
- case 'l': if(is("lex")||is("_^Hl_^He_^Hx"))
- { if(inlex)syntax("nested %lex not permitted\n");
- /* due to use of global vars inlex, lexdefs */
- return(LEX); }
- if(is("list")||is("_l_i_s_t"))
- { echoing=verbosity; return(yylex()); }
- break;
- case 'n': if(is("nolist")||is("_n_o_l_i_s_t"))
- { echoing=0; return(yylex()); }
- break;
- }
- if(echoing)putchar('\n');
- printf("syntax error: unknown directive \"%%%s\"\n",dicp),
- acterror();
- return(END);
-}
-
-okid(ch)
-word ch;
-{ return('a'<=ch&&ch<='z'||'A'<=ch&&ch<='Z'||'0'<=ch&&ch<='9'
- ||ch=='_'||ch=='\''); }
-
-okulid(ch)
-word ch;
-{ return('a'<=ch&&ch<='z'||'A'<=ch&&ch<='Z'||'0'<=ch&&ch<='9'
- ||ch=='_'||ch==''||ch=='\''); }
-
-kollect(f)
-/* note top of dictionary used as work space to collect current token */
-word (*f)();
-{ dicq= dicp;
- while((*f)(c)){ *dicq++ = c; c= getch(); }
- *dicq++ = '\0';
- ovflocheck;
-}
-
-char *keep(p) /* call this to retain volatile string for later use */
-char *p;
-{ if(p==dicp)dicp= dicq;
- else (void)strcpy(dicp,p),
- p=dicp,
- dicp=dicq=dicp+strlen(dicp)+1,
- dic_check();
- return(p);
-}
-
-dic_check() /* called from REDUCE */
-{ ovflocheck; }
-
-numeral()
-{ word nflag=1;
- dicq= dicp;
- while(isdigit(c))
- *dicq++ = c, c=getch();
- if(c=='.'&&peekdig())
- { *dicq++ = c, c=getch(); nflag=0;
- while(isdigit(c))
- *dicq++ = c, c=getch(); }
- if(c=='e')
- { word np=0;
- *dicq++ = c, c=getch(); nflag=0;
- if(c=='+')c=getch(); else /* ignore + before exponent */
- if(c=='-')*dicq++ = c, c=getch();
- if(!isdigit(c)) /* e must be followed by some digits */
- syntax("badly formed floating point number\n");
- while(c=='0')
- *dicq++ = c, c=getch();
- while(isdigit(c))
- np++, *dicq++ = c, c=getch();
- if(!nflag&&np>3) /* scanf falls over with silly exponents */
- { syntax("floating point number out of range\n");
- return; }
- }
- ovflocheck;
- if(nflag) /* `.' or `e' makes fractional */
- *dicq = '\0',
- yylval= bigscan(dicp); else
- { double r=0.0;
- if(dicq-dicp>60) /* this allows 59 chars */
- /* scanf crashes, on VAX, gives wrong answers, on ORION 1/05 */
- { syntax("illegal floating point constant (too many digits)\n");
- return; }
- errno=0;
- *dicq = '\n';
- sscanf(dicp,"%lf",&r);
- if(errno)fpe_error(); else
- yylval= sto_dbl((double)r); }
-}
-
-hexnumeral() /* added 21.11.2013 */
-{ extern word errno;
- word nflag=1;
- dicq= dicp;
- *dicq++ = c, c=getch(); /* 0 */
- *dicq++ = c, c=getch(); /* x */
- if(!isxdigit(c)&&c!='.')syntax("malformed hex number\n");
- while(c=='0'&&isxdigit(peekch()))c=getch(); /* skip zeros before first nonzero digit */
- while(isxdigit(c))
- *dicq++ = c, c=getch();
- ovflocheck;
- if(c=='.'||tolower(c)=='p') /* hex float, added 20.11.19 */
- { double d;
- if(c=='.')
- { *dicq++ = c, c=getch();
- while(isxdigit(c))
- *dicq++ = c, c=getch(); }
- if(c=='p')
- { *dicq++ = c, c=getch();
- if(c=='+'||c=='-')*dicq++ = c, c=getch();
- if(!isdigit(c))syntax("malformed hex float\n");
- while(isdigit(c))
- *dicq++ = c, c=getch(); }
- ovflocheck;
- *dicq='\0';
- if(dicq-dicp>60||sscanf(dicp,"%lf",&d)!=1)
- syntax("malformed hex float\n");
- else yylval= sto_dbl(d);
- return; }
- *dicq = '\0';
- yylval= bigxscan(dicp+2,dicq);
-}
-
-octnumeral() /* added 21.11.2013 */
-{ extern word errno;
- word nflag=1;
- dicq= dicp;
- if(!isdigit(c))syntax("malformed octal number\n");
- while(c=='0'&&isdigit(peekch()))c=getch(); /* skip zeros before first nonzero digit */
- while(isdigit(c)&&c<='7')
- *dicq++ = c, c=getch();
- if(isdigit(c))syntax("illegal digit in octal number\n");
- ovflocheck;
- *dicq = '\0';
- yylval= bigoscan(dicp,dicq);
-}
-
-word namebucket[128]; /* each namebucket has a list terminated by 0, not NIL */
-
-hash(s) /* returns a value in {0..127} */
-char *s;
-{ word h = *s;
- if(h)while(*++s)h ^= *s; /* guard necessary to deal with s empty */
- return(h&127);
-}
-
-isconstrname(s)
-char *s;
-{ if(s[0]=='$')s++;
- return isupper(*s); /* formerly !islower */
-}
-
-getfname(x)
-/* nonterminals have an added ' ', getfname returns the corresponding
- function name */
-word x;
-{ char *p = get_id(x);
- dicq= dicp;
- while(*dicq++ = *p++);
- if(dicq-dicp<3)fprintf(stderr,"impossible event in getfname\n"),exit(1);
- dicq[-2] = '\0'; /* overwrite last char */
- ovflocheck;
- return(name());
-}
-
-isnonterminal(x)
-word x;
-{ char *n;
- if(tag[x]!=ID)return(0);
- n = get_id(x);
- return(n[strlen(n)-1]==' ');
-}
-
-name()
-{ word q,h;
- q= namebucket[h=hash(dicp)];
- while(q&&!is(get_id(hd[q])))q= tl[q];
- if(q==0)
- { q = sto_id(dicp);
- namebucket[h] = cons(q,namebucket[h]);
- keep(dicp); }
- else q= hd[q];
- return(q); }
-/* note - keeping buckets sorted didn't seem to help (if anything slightly
- slower) probably because ordering only relevant if name not present, and
- outweighed by increased complexity of loop */
-
-static word inprelude=1;
-
-make_id(n) /* used in mira_setup(), primdef(), predef(), all in steer.c */
-char *n;
-{ word x,h;
- h=hash(n);
- x = sto_id(inprelude?keep(n):n);
- namebucket[h] = cons(x,namebucket[h]);
- return(x); }
-
-findid(n) /* like name() but returns NIL rather than create new id */
-char *n;
-{ word q;
- q= namebucket[hash(n)];
- while(q&&!strcmp(n,get_id(hd[q]))==0)q= tl[q];
- return(q?hd[q]:NIL); }
-
-word *pnvec=0,nextpn,pn_lim=200; /* private name vector */
-
-reset_pns() /* (re)initialise private name space */
-{ nextpn=0;
- if(!pnvec)
- { pnvec=(word *)malloc(pn_lim*sizeof(word));
- if(pnvec==NULL)mallocfail("pnvec"); }
-}
-
-make_pn(val) /* create new private name with value val */
-word val;
-{ if(nextpn==pn_lim)
- { pn_lim+=400;
- pnvec=(word *)realloc(pnvec,pn_lim*sizeof(word));
- if(pnvec==NULL)mallocfail("pnvec"); }
- pnvec[nextpn]=strcons(nextpn,val);
- return(pnvec[nextpn++]);
-}
-
-sto_pn(n) /* return n'th private name, extending pnvec if necessary */
-word n;
-{ if(n>=pn_lim)
- { while(pn_lim<=n)pn_lim+=400;
- pnvec=(word *)realloc(pnvec,pn_lim*sizeof(word));
- if(pnvec==NULL)mallocfail("pnvec"); }
- while(nextpn<=n) /* NB allocates all missing names upto and including nth*/
- pnvec[nextpn]=strcons(nextpn,UNDEF),nextpn++;
- return(pnvec[n]);
-}
-
-mkprivate(x) /* disguise identifiers prior to removal from environment */
-word x; /* used in setting up prelude - see main() in steer.c */
-{ while(x!=NIL)
- { char *s = get_id(hd[x]);
- get_id(hd[x])[0] += 128; /* hack to make private internal name */
- x = tl[x]; } /* NB - doesn't change hashbucket */
- inprelude=0;
-}
-
-word sl=100;
-
-string()
-{ word p;
- word ch,badch=0;
- c = getch();
- ch= getlitch();
- p= yylval= cons(NIL,NIL);
- while(ch!=EOF&&rawch!='\"'&&rawch!='\n')
- if(ch==-7) ch=getlitch(); else /* skip \& */
- if(ch<0){ badch=ch; break; }
- else { p= tl[p]= cons(ch,NIL);
- ch= getlitch(); }
- yylval= tl[yylval];
- if(badch)errclass(badch,1);
- if(rawch=='\n')
- syntax("non-escaped newline encountered inside string quotes\n"); else
- if(ch==EOF)
- { if(echoing)putchar('\n');
- printf("syntax error: script ends inside unclosed string quotes - \n");
- printf(" \"");
- while(yylval!=NIL&& sl-- )
- { putchar(hd[yylval]);
- yylval= tl[yylval]; }
- printf("...\"\n");
- acterror(); }
-}
-
-charclass()
-{ word p;
- word ch,badch=0,anti=0;
- c = getch();
- if(c=='^')anti=1,c=getch();
- ch= getlitch();
- p= yylval= cons(NIL,NIL);
- while(ch!=EOF&&rawch!='`'&&rawch!='\n')
- if(ch==-7)ch=getlitch(); else /* skip \& */
- if(ch<0){ badch=ch; break; }
- else { if(rawch=='-'&&hd[p]!=NIL&&hd[p]!=DOTDOT)
- ch=DOTDOT; /* non-initial, non-escaped '-' */
- p= tl[p]= cons(ch,NIL);
- ch= getlitch(); }
- if(hd[p]==DOTDOT)hd[p]='-'; /* naturalise a trailing '-' */
- for(p=yylval;tl[p]!=NIL;p=tl[p]) /* move each DOTDOT to front of range */
- if(hd[tl[p]]==DOTDOT)
- { hd[tl[p]]=hd[p],hd[p]=DOTDOT;
- if(hd[tl[p]]>=hd[tl[tl[p]]])
- syntax("illegal use of '-' in [charclass]\n");
- }
- yylval= tl[yylval];
- if(badch)errclass(badch,2);
- if(rawch=='\n')
- syntax("non-escaped newline encountered in char class\n"); else
- if(ch==EOF)
- { if(echoing)putchar('\n');
- printf(
- "syntax error: script ends inside unclosed char class brackets - \n");
- printf(" [");
- while(yylval!=NIL&& sl-- )
- { putchar(hd[yylval]);
- yylval= tl[yylval]; }
- printf("...]\n");
- acterror(); }
- return(anti);
-}
-
-reset_lex() /* called after an error */
-{ extern word errs,errline;
- extern char *current_script;
- /*printf("reset_lex()\n"); /* DEBUG */
- if(!commandmode)
- { if(!errs)errs=fileinfo(get_fil(current_file),line_no);
- /* convention, if errs set contains location of error, otherwise pick up
- from current_file and line_no */
- if(tl[errs]==0&&(char *)hd[errs]==current_script)
- /* at end of file, so line_no has been reset to 0 */
- printf("error occurs at end of ");
- else printf("error found near line %d of ",tl[errs]);
- printf("%sfile \"%s\"\ncompilation abandoned\n",
- (char *)hd[errs]==current_script?"":"%insert ",
- (char *)hd[errs]);
- if((char *)hd[errs]==current_script)
- errline=tl[errs]==0?lastline:tl[errs],errs=0;
- else { while(tl[linostack]!=NIL)linostack=tl[linostack];
- errline=hd[linostack]; }
- /* tells editor where to find error - errline contains location of 1st
- error in main script, errs is hereinfo of upto one error in %insert
- script (each is 0 if not set) - some errors can set both */
- }
- reset_state();
-}
-
-reset_state() /* reset all global variables used by compiler */
-{ extern word TABSTRS,SGC,newtyps,algshfns,showchain,inexplist,sreds,
- rv_script,idsused;
- /* printf("reset_state()\n"); /* DEBUG */
- if(commandmode)
- while(c!='\n'&&c!=EOF)c=getc(s_in); /* no echo */
- while(fileq!=NIL)fclose((FILE *)hd[hd[fileq]]),fileq=tl[fileq];
- insertdepth= -1;
- s_in=stdin;
- echostack=idsused=prefixstack=litstack=linostack=vergstack
- =margstack=NIL;
- prefix=0; prefixbase[0]='\0';
- echoing=verbosity&listing;
- brct=inbnf=sreds=inlex=inexplist=commandmode=lverge=col=lmargin=0;
- atnl=1;
- rv_script=0;
- algshfns=newtyps=showchain=SGC=TABSTRS=NIL;
- c=' ';
- line_no=0;
- litmain=literate=0;
- /* printf("exit reset_state()\n"); /* DEBUG */
-}
-
-/* end of MIRANDA LEX ANALYSER */
-
diff --git a/new/reduce.c b/new/reduce.c
deleted file mode 100644
index 04f7267..0000000
--- a/new/reduce.c
+++ /dev/null
@@ -1,2376 +0,0 @@
-/* MIRANDA REDUCE */
-/* new SK reduction machine - installed Oct 86 */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-struct stat buf; /* used only by code for FILEMODE, FILESTAT in reduce */
-#include "data.h"
-#include "big.h"
-#include "lex.h"
-extern word debug, UTF8, UTF8OUT;
-#define FST HD
-#define SND TL
-#define BSDCLOCK
-/* POSIX clock wraps around after c. 72 mins */
-#ifdef RYU
-char* d2s(double);
-word d2s_buffered(double, char*);
-#endif
-
-double fa,fb;
-long long cycles=0;
-word stdinuse=0;
-/* int lasthead=0; /* DEBUG */
-
-#define constr_tag(x) hd[x]
-#define idconstr_tag(x) hd[id_val(x)]
-#define constr_name(x) (tag[tl[x]]==ID?get_id(tl[x]):get_id(pn_val(tl[x])))
-#define suppressed(x) (tag[tl[x]]==STRCONS&&tag[pn_val(tl[x])]!=ID)
- /* suppressed constructor */
-
-#define isodigit(x) ('0'<=(x) && (x)<='7')
-#define sign(x) (x)
-#define fsign(x) ((d=(x))<0?-1:d>0)
-/* ### */ /* functions marked ### contain possibly recursive calls
- to reduce - fix later */
-
-compare(a,b) /* returns -1, 0, 1 as a is less than equal to or greater than
- b in the ordering imposed on all data types by the miranda
- language -- a and b already reduced */
- /* used by MATCH, EQ, NEQ, GR, GRE */
-word a,b;
-{ double d;
- L: switch(tag[a])
- { case DOUBLE:
- if(tag[b]==DOUBLE)return(fsign(get_dbl(a)-get_dbl(b)));
- else return(fsign(get_dbl(a)-bigtodbl(b)));
- case INT:
- if(tag[b]==INT)return(bigcmp(a,b));
- else return(fsign(bigtodbl(a)-get_dbl(b)));
- case UNICODE: return sign(get_char(a)-get_char(b));
- case ATOM:
- if(tag[b]==UNICODE) return sign(get_char(a)-get_char(b));
- if(S<=a&&a<=ERROR||S<=b&&b<=ERROR)
- fn_error("attempt to compare functions");
- /* what about constructors - FIX LATER */
- if(tag[b]==ATOM)return(sign(a-b)); /* order of declaration */
- else return(-1); /* atomic object always less than non-atomic */
- case CONSTRUCTOR:
- if(tag[b]==CONSTRUCTOR)
- return(sign(constr_tag(a)-constr_tag(b))); /*order of declaration*/
- else return(-1); /* atom less than non-atom */
- case CONS: case AP:
- if(tag[a]==tag[b])
- { word temp;
- hd[a]=reduce(hd[a]);
- hd[b]=reduce(hd[b]);
- if((temp=compare(hd[a],hd[b]))!=0)return(temp);
- a=tl[a]=reduce(tl[a]);
- b=tl[b]=reduce(tl[b]);
- goto L; }
- else if(S<=b&&b<=ERROR)fn_error("attempt to compare functions");
- else return(1); /* non-atom greater than atom */
- default: fprintf(stderr,"\nghastly error in compare\n");
- }
- return(0);
-}
-
-force(x) /* ensures that x is evaluated "all the way" */
-word x; /* x is already reduced */ /* ### */
-{ word h;
- switch(tag[x])
- { case AP: h=hd[x];
- while(tag[h]==AP)h=hd[h];
- if(S<=h&&h<=ERROR)return; /* don't go inside functions */
- /* what about unsaturated constructors? fix later */
- while(tag[x]==AP)
- { tl[x]=reduce(tl[x]);
- force(tl[x]);
- x=hd[x]; }
- return;
- case CONS: while(tag[x]==CONS)
- { hd[x]=reduce(hd[x]);
- force(hd[x]);
- x=tl[x]=reduce(tl[x]); }
- }
- return;
-}
-
-head(x) /* finds the function part of x */
-word x;
-{ while(tag[x]==AP)x= hd[x];
- return(x);
-}
-
-extern char linebuf[]; /* used as workspace in various places */
-
-/* ### */ /* opposite is str_conv - see lex.c */
-char *getstring(x,cmd) /* collect Miranda string - x is already reduced */
-word x;
-char *cmd; /* context, for error message */
-{ word x1=x,n=0;
- char *p=linebuf;
- while(tag[x]==CONS&&n<BUFSIZE)
- n++, hd[x] = reduce(hd[x]), x=tl[x]=reduce(tl[x]);
- x=x1;
- while(tag[x]==CONS&&n--)
- *p++ = hd[x], x=tl[x];
- *p++ ='\0';
- if(p-linebuf>BUFSIZE)
- { if(cmd)fprintf(stderr,
- "\n%s, argument string too long (limit=%d chars): %s...\n",
- cmd,BUFSIZE,linebuf),
- outstats(),
- exit(1);
- else return(linebuf); /* see G_CLOSE */ }
- return(linebuf); /* very inefficient to keep doing this for filenames etc.
- CANNOT WE SUPPORT A PACKED REPRESENTATION OF STRINGS? */
-} /* call keep(linebuf) if you want to save the string */
-
-FILE *s_out=NULL; /* destination of current output message */
- /* initialised in main() */
-#define Stdout 0
-#define Stderr 1
-#define Tofile 2
-#define Closefile 3
-#define Appendfile 4
-#define System 5
-#define Exit 6
-#define Stdoutb 7
-#define Tofileb 8
-#define Appendfileb 9
- /* order of declaration of constructors of these names in sys_message */
-
-/* ### */
-output(e) /* "output" is called by YACC (see MIRANDA RULES) to print the
- value of an expression - output then calls "reduce" - so the
- whole reduction process is driven by the need to print */
- /* the value of the whole expression is a list of `messages' */
-word e;
-{
- extern word *cstack;
- cstack = &e; /* don't follow C stack below this in gc */
-L:e= reduce(e);
- while(tag[e]==CONS)
- { word d;
- hd[e]= reduce(hd[e]);
- switch(constr_tag(head(hd[e])))
- { case Stdout: print(tl[hd[e]]);
- break;
- case Stdoutb: UTF8OUT=0;
- print(tl[hd[e]]);
- UTF8OUT=UTF8;
- break;
- case Stderr: s_out=stderr; print(tl[hd[e]]); s_out=stdout;
- break;
- case Tofile: outf(hd[e]);
- break;
- case Tofileb: UTF8OUT=0;
- outf(hd[e]);
- UTF8OUT=UTF8;
- break;
- case Closefile: closefile(tl[hd[e]]=reduce(tl[hd[e]]));
- break;
- case Appendfile: apfile(tl[hd[e]]=reduce(tl[hd[e]]));
- break;
- case Appendfileb: UTF8OUT=0;
- apfile(tl[hd[e]]=reduce(tl[hd[e]]));
- UTF8OUT=UTF8;
- break;
- case System: system(getstring(tl[hd[e]]=reduce(tl[hd[e]]),"System"));
- break;
- case Exit: { word n=reduce(tl[hd[e]]);
- if(tag[n]==INT)n=digit0(n);
- else word_error("Exit");
- outstats(); exit(n); }
- default: fprintf(stderr,"\n<impossible event in output list: ");
- out(stderr,hd[e]);
- fprintf(stderr,">\n"); }
- e= tl[e]= reduce(tl[e]);
- }
- if(e==NIL)return;
- fprintf(stderr,"\nimpossible event in output\n"),
- putc('<',stderr),out(stderr,e),fprintf(stderr,">\n");
- exit(1);
-}
-
-/* ### */
-print(e) /* evaluate list of chars and send to s_out */
-word e;
-{ e= reduce(e);
- while(tag[e]==CONS && is_char(hd[e]=reduce(hd[e])))
- { unsigned word c=get_char(hd[e]);
- if(UTF8)outUTF8(c,s_out); else
- if(c<256) putc(c,s_out);
- else fprintf(stderr,"\n warning: non Latin1 char \%x in print, ignored\n",c);
- e= tl[e]= reduce(tl[e]); }
- if(e==NIL)return;
- fprintf(stderr,"\nimpossible event in print\n"),
- putc('<',stderr),out(stderr,e),fprintf(stderr,">\n"),
- exit(1);
-}
-
-word outfilq=NIL; /* list of opened-for-output files */
-/* note that this will be automatically reset to NIL and all files on it
-closed at end of expression evaluation, because of the fork-exit structure */
-
-/* ### */
-outf(e) /* e is of the form (Tofile f x) */
-word e;
-{ word p=outfilq; /* have we already opened this file for output? */
- char *f=getstring(tl[hd[e]]=reduce(tl[hd[e]]),"Tofile");
- while(p!=NIL && strcmp((char *)hd[hd[p]],f)!=0)p=tl[p];
- if(p==NIL) /* new output file */
- { s_out= fopen(f,"w");
- if(s_out==NULL)
- { fprintf(stderr,"\nTofile: cannot write to \"%s\"\n",f);
- s_out=stdout;
- return;
- /* outstats(); exit(1); /* release one policy */
- }
- if(isatty(fileno(s_out)))setbuf(s_out,NULL); /*for unbuffered tty output*/
- outfilq= cons(datapair(keep(f),s_out),outfilq); }
- else s_out= (FILE *)tl[hd[p]];
- print(tl[e]);
- s_out= stdout;
-}
-
-apfile(f) /* open file of name f for appending and add to outfilq */
-word f;
-{ word p=outfilq; /* is it already open? */
- char *fil=getstring(f,"Appendfile");
- while(p!=NIL && strcmp((char *)hd[hd[p]],fil)!=0)p=tl[p];
- if(p==NIL) /* no, so open in append mode */
- { FILE *s=fopen(fil,"a");
- if(s==NULL)
- fprintf(stderr,"\nAppendfile: cannot write to \"%s\"\n",fil);
- else outfilq= cons(datapair(keep(fil),s),outfilq);
- }
- /* if already there do nothing */
-}
-
-closefile(f) /* remove file of name "f" from outfilq and close stream */
-word f;
-{ word *p= &outfilq; /* is this file open for output? */
- char *fil=getstring(f,"Closefile");
- while(*p!=NIL && strcmp((char *)hd[hd[*p]],fil)!=0)p= &tl[*p];
- if(*p!=NIL) /* yes */
- { fclose((FILE *)tl[hd[*p]]);
- *p=tl[*p]; /* remove link from outfilq */}
- /* otherwise ignore closefile request (harmless??) */
-}
-
-static word errtrap=0; /* to prevent error cycles - see ERROR below */
-word waiting=NIL;
-/* list of terminated child processes with exit_status - see Exec/EXEC */
-
-/* pointer-reversing SK reduction machine - based on code written Sep 83 */
-
-#define BACKSTOP 020000000000
-#define READY(x) (x)
-#define RESTORE(x)
-/* in this machine the above two are no-ops, alternate definitions are, eg
-#define READY(x) (x+1)
-#define RESTORE(x) x--
-(if using this method each strict comb needs next opcode unallocated)
- see comment before "ready" switch */
-#define FIELD word
-#define tlptrbit 020000000000
-#define tlptrbits 030000000000
- /* warning -- if you change this tell `mark()' in data.c */
-#define mktlptr(x) x |= tlptrbit
-#define mk1tlptr x |= tlptrbits
-#define mknormal(x) x &= ~tlptrbits
-#define abnormal(x) ((x)<0)
-/* covers x is tlptr and x==BACKSTOP */
-
-/* control abstractions */
-
-#define setcell(t,a,b) tag[e]=t,hd[e]=a,tl[e]=b
-#define DOWNLEFT hold=s, s=e, e=hd[e], hd[s]=hold
-#define DOWNRIGHT hold=hd[s], hd[s]=e, e=tl[s], tl[s]=hold, mktlptr(s)
-#define downright if(abnormal(s))goto DONE; DOWNRIGHT
-#define UPLEFT hold=s, s=hd[s], hd[hold]=e, e=hold
-#define upleft if(abnormal(s))goto DONE; UPLEFT
-#define GETARG(a) UPLEFT, a=tl[e]
-#define getarg(a) upleft; a=tl[e]
-#define UPRIGHT mknormal(s), hold=tl[s], tl[s]=e, e=hd[s], hd[s]=hold
-#define lastarg tl[e]
-word reds=0;
-
-/* IMPORTANT WARNING - the macro's
- `downright;' `upleft;' `getarg;'
- MUST BE ENCLOSED IN BRACES when they occur as the body of a control
- structure (if, while etc.) */
-
-#define simpl(r) hd[e]=I, e=tl[e]=r
-
-#ifdef DEBUG
-word maxrdepth=0,rdepth=0;
-#endif
-
-#define fails(x) (x==NIL)
-#define FAILURE NIL
- /* used by grammar combinators */
-
-/* reduce e to hnf, note that a function in hnf will have head h with
- S<=h<=ERROR all combinators lie in this range see combs.h */
-FIELD reduce(e)
-FIELD e;
-{ FIELD s=BACKSTOP,hold,arg1,arg2,arg3;
-#ifdef DEBUG
- if(++rdepth>maxrdepth)maxrdepth=rdepth;
- if(debug&02)
- printf("reducing: "),out(stdout,e),putchar('\n');
-#endif
-
- NEXTREDEX:
- while(!abnormal(e)&&tag[e]==AP)DOWNLEFT;
-#ifdef HISTO
- histo(e);
-#endif
-#ifdef DEBUG
- if(debug&02)
- { printf("head= ");
- if(e==BACKSTOP)printf("BACKSTOP");
- else out(stdout,e);
- putchar('\n'); }
-#endif
-
- OPDECODE:
-/*lasthead=e; /* DEBUG */
- cycles++;
- switch(e)
- {
- case S: /* S f g x => f x(g x) */
- getarg(arg1);
- getarg(arg2);
- upleft;
- hd[e]=ap(arg1,lastarg); tl[e]=ap(arg2,lastarg);
- DOWNLEFT;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case B: /* B f g x => f(g z) */
- getarg(arg1);
- getarg(arg2);
- upleft;
- hd[e]=arg1; tl[e]=ap(arg2,lastarg);
- DOWNLEFT;
- goto NEXTREDEX;
-
- case CB: /* CB f g x => g(f z) */
- getarg(arg1);
- getarg(arg2);
- upleft;
- hd[e]=arg2; tl[e]=ap(arg1,lastarg);
- DOWNLEFT;
- goto NEXTREDEX;
-
- case C: /* C f g x => f x g */
- getarg(arg1);
- getarg(arg2);
- upleft;
- hd[e]=ap(arg1,lastarg); tl[e]=arg2;
- DOWNLEFT;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case Y: /* Y h => self where self=(h self) */
- upleft;
- hd[e]=tl[e]; tl[e]=e;
- DOWNLEFT;
- goto NEXTREDEX;
-
- L_K:
- case K: /* K x y => x */
- getarg(arg1);
- upleft;
- hd[e]=I; e=tl[e]=arg1;
- goto NEXTREDEX; /* could make eager in first arg */
-
- L_KI:
- case KI: /* KI x y => y */
- upleft; /* lose first arg */
- upleft;
- hd[e]=I; e=lastarg; /* ?? */
- goto NEXTREDEX; /* could make eager in 2nd arg */
-
- case S1: /* S1 k f g x => k(f x)(g x) */
- getarg(arg1);
- getarg(arg2);
- getarg(arg3);
- upleft;
- hd[e]=ap(arg2,lastarg);
- hd[e]=ap(arg1,hd[e]);
- tl[e]=ap(arg3,lastarg);
- DOWNLEFT;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case B1: /* B1 k f g x => k(f(g x)) */
- getarg(arg1); /* Mark Scheevel's new B1 */
- getarg(arg2);
- getarg(arg3);
- upleft;
- hd[e]=arg1;
- tl[e]=ap(arg3,lastarg);
- tl[e]=ap(arg2,tl[e]);
- DOWNLEFT;
- goto NEXTREDEX;
-
- case C1: /* C1 k f g x => k(f x)g */
- getarg(arg1);
- getarg(arg2);
- getarg(arg3);
- upleft;
- hd[e]=ap(arg2,lastarg);
- hd[e]=ap(arg1,hd[e]);
- tl[e]=arg3;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case S_p: /* S_p f g x => (f x) : (g x) */
- getarg(arg1);
- getarg(arg2);
- upleft;
- setcell(CONS,ap(arg1,lastarg),ap(arg2,lastarg));
- goto DONE;
-
- case B_p: /* B_p f g x => f : (g x) */
- getarg(arg1);
- getarg(arg2);
- upleft;
- setcell(CONS,arg1,ap(arg2,lastarg));
- goto DONE;
-
- case C_p: /* C_p f g x => (f x) : g */
- getarg(arg1);
- getarg(arg2);
- upleft;
- setcell(CONS,ap(arg1,lastarg),arg2);
- goto DONE;
-
- case ITERATE: /* ITERATE f x => x:ITERATE f (f x) */
- getarg(arg1);
- upleft;
- hold=ap(hd[e],ap(arg1,lastarg));
- setcell(CONS,lastarg,hold);
- goto DONE;
-
- case ITERATE1: /* ITERATE1 f x => [], x=FAIL
- => x:ITERATE1 f (f x), otherwise */
- getarg(arg1);
- upleft;
- if((lastarg=reduce(lastarg))==FAIL) /* ### */
- { hd[e]=I; e=tl[e]=NIL; }
- else
- { hold=ap(hd[e],ap(arg1,lastarg));
- setcell(CONS,lastarg,hold); }
- goto DONE;
-
- case G_RULE:
- case P: /* P x y => x:y */
- getarg(arg1);
- upleft;
- setcell(CONS,arg1,lastarg);
- goto DONE;
-
- case U: /* U f x => f (HD x) (TL x)
- non-strict uncurry */
- getarg(arg1);
- upleft;
- hd[e]=ap(arg1,ap(HD,lastarg));
- tl[e]=ap(TL,lastarg);
- DOWNLEFT;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case Uf: /* Uf f x => f (BODY x) (LAST x)
- version of non-strict U for
- arbitrary constructors */
- getarg(arg1);
- upleft;
- if(tag[head(lastarg)]==CONSTRUCTOR) /* be eager if safe */
- hd[e]=ap(arg1,hd[lastarg]),
- tl[e]=tl[lastarg];
- else
- hd[e]=ap(arg1,ap(BODY,lastarg)),
- tl[e]=ap(LAST,lastarg);
- DOWNLEFT;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case ATLEAST: /* ATLEAST k f x => f(x-k), isnat x & x>=k
- => FAIL, otherwise */
- /* for matching n+k patterns */
- getarg(arg1);
- getarg(arg2);
- upleft;
- lastarg= reduce(lastarg); /* ### */
- if(tag[lastarg]==INT)
- { hold = bigsub(lastarg,arg1);
- if(poz(hold))hd[e]=arg2,tl[e]=hold;
- else hd[e]=I,e=tl[e]=FAIL; }
- else hd[e]=I,e=tl[e]=FAIL;
- goto NEXTREDEX;
-
- case U_: /* U_ f (a:b) => f a b
- U_ f other => FAIL
- U_ is a strict version of U(see above) */
- getarg(arg1);
- upleft;
- lastarg= reduce(lastarg); /* ### */
- if(lastarg==NIL)
- { hd[e]=I;
- e=tl[e]=FAIL;
- goto NEXTREDEX; }
- hd[e]=ap(arg1,hd[lastarg]);
- tl[e]=tl[lastarg];
- goto NEXTREDEX;
-
- case Ug: /* Ug k f (k x1 ... xn) => f x1 ... xn, n>=0
- Ug k f other => FAIL
- Ug is a strict version of U for arbitrary constructor k */
- getarg(arg1);
- getarg(arg2);
- upleft;
- lastarg= reduce(lastarg); /* ### */
- if(constr_tag(arg1)!=constr_tag(head(lastarg)))
- { hd[e]=I;
- e=tl[e]=FAIL;
- goto NEXTREDEX; }
- if(tag[lastarg]==CONSTRUCTOR) /* case n=0 */
- { hd[e]=I; e=tl[e]=arg2; goto NEXTREDEX; }
- hd[e]=hd[lastarg];
- tl[e]=tl[lastarg];
- while(tag[hd[e]]!=CONSTRUCTOR)
- /* go back to head of arg3, copying spine */
- { hd[e]=ap(hd[hd[e]],tl[hd[e]]);
- DOWNLEFT; }
- hd[e]=arg2; /* replace k with f */
- goto NEXTREDEX;
-
- case MATCH: /* MATCH a f a => f
- MATCH a f b => FAIL */
- upleft;
- arg1=lastarg=reduce(lastarg); /* ### */
- /* note that MATCH evaluates arg1, usually needless, could have second
- version - MATCHEQ, say */
- getarg(arg2);
- upleft;
- lastarg=reduce(lastarg); /* ### */
- hd[e]=I;
- e=tl[e]=compare(arg1,lastarg)?FAIL:arg2;
- goto NEXTREDEX;
-
- case MATCHINT: /* same but 1st arg is integer literal */
- getarg(arg1);
- getarg(arg2);
- upleft;
- lastarg=reduce(lastarg); /* ### */
- hd[e]=I;
- e=tl[e]=(tag[lastarg]!=INT||bigcmp(arg1,lastarg))?FAIL:arg2;
- /* note no coercion from INT to DOUBLE here */
- goto NEXTREDEX;
-
- case GENSEQ: /* GENSEQ (i,NIL) a => a:GENSEQ (i,NIL) (a+i)
- GENSEQ (i,b) a => [], a>b=sign
- => a:GENSEQ (i,b) (a+i), otherwise
- where
- sign = 1, i>=0
- = -1, otherwise */
- GETARG(arg1);
- UPLEFT;
- if(tl[arg1]!=NIL&&
- (tag[arg1]==AP?compare(lastarg,tl[arg1]):compare(tl[arg1],lastarg))>0)
- hd[e]=I, e=tl[e]=NIL;
- else hold=ap(hd[e],numplus(lastarg,hd[arg1])),
- setcell(CONS,lastarg,hold);
- goto DONE;
- /* efficiency hack - tag of arg1 encodes sign of step */
-
- case MAP: /* MAP f [] => []
- MAP f (a:x) => f a : MAP f x */
- getarg(arg1);
- upleft;
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==NIL)
- hd[e]=I, e=tl[e]=NIL;
- else hold=ap(hd[e],tl[lastarg]),
- setcell(CONS,ap(arg1,hd[lastarg]),hold);
- goto DONE;
-
- case FLATMAP: /* funny version of map for compiling zf exps
- FLATMAP f [] => []
- FLATMAP f (a:x) => FLATMAP f x, f a=FAIL
- => f a ++ FLATMAP f x
- (FLATMAP was formerly called MAP1) */
- getarg(arg1);
- getarg(arg2);
- L1:arg2=reduce(arg2); /* ### */
- if(arg2==NIL)
- { hd[e]=I;
- e=tl[e]=NIL;
- goto DONE; }
- hold=reduce(hold=ap(arg1,hd[arg2]));
- if(hold==FAIL||hold==NIL){ arg2=tl[arg2]; goto L1; }
- tl[e]=ap(hd[e],tl[arg2]);
- hd[e]=ap(APPEND,hold);
- goto NEXTREDEX;
-
- case FILTER: /* FILTER f [] => []
- FILTER f (a:x) => a : FILTER f x, f a
- => FILTER f x, otherwise */
- getarg(arg1);
- upleft;
- lastarg=reduce(lastarg); /* ### */
- while(lastarg!=NIL&&reduce(ap(arg1,hd[lastarg]))==False) /* ### */
- lastarg=reduce(tl[lastarg]); /* ### */
- if(lastarg==NIL)
- hd[e]=I, e=tl[e]=NIL;
- else hold=ap(hd[e],tl[lastarg]),
- setcell(CONS,hd[lastarg],hold);
- goto DONE;
-
- case LIST_LAST: /* LIST_LAST x => x!(#x-1) */
- upleft;
- if((lastarg=reduce(lastarg))==NIL)fn_error("last []"); /* ### */
- while((tl[lastarg]=reduce(tl[lastarg]))!=NIL) /* ### */
- lastarg=tl[lastarg];
- hd[e]=I; e=tl[e]=hd[lastarg];
- goto NEXTREDEX;
-
- case LENGTH: /* takes length of a list */
- upleft;
- { long long n=0; /* problem - may be followed by gc */
- /* cannot make static because of ### below */
- while((lastarg=reduce(lastarg))!=NIL) /* ### */
- lastarg=tl[lastarg],n++;
- simpl(sto_word(n)); }
- goto DONE;
-
- case DROP:
- getarg(arg1);
- upleft;
- arg1=tl[hd[e]]=reduce(tl[hd[e]]); /* ### */
- if(tag[arg1]!=INT)word_error("drop");
- { long long n=get_word(arg1);
- while(n-- >0)
- if((lastarg=reduce(lastarg))==NIL) /* ### */
- { simpl(NIL); goto DONE; }
- else lastarg=tl[lastarg]; }
- simpl(lastarg);
- goto NEXTREDEX;
-
- case SUBSCRIPT: /* SUBSCRIPT i x => x!i */
- upleft;
- upleft;
- arg1=tl[hd[e]]=reduce(tl[hd[e]]); /* ### */
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==NIL)subs_error();
- { long long indx = tag[arg1]==ATOM?arg1:/* small indexes represented directly */
- tag[arg1]==INT?get_word(arg1):
- word_error("!");
- /* problem, indx may be followed by gc
- - cannot make static, because of ### below */
- if(indx<0)subs_error();
- while(indx)
- { lastarg= tl[lastarg]= reduce(tl[lastarg]); /* ### */
- if(lastarg==NIL)subs_error();
- indx--; }
- hd[e]= I;
- e=tl[e]=hd[lastarg]; /* could be eager in tl[e] */
- goto NEXTREDEX; }
-
- case FOLDL1: /* FOLDL1 op (a:x) => FOLDL op a x */
- getarg(arg1);
- upleft;
- if((lastarg=reduce(lastarg))!=NIL) /* ### */
- { hd[e]=ap2(FOLDL,arg1,hd[lastarg]);
- tl[e]=tl[lastarg];
- goto NEXTREDEX; }
- else fn_error("foldl1 applied to []");
-
- case FOLDL: /* FOLDL op r [] => r
- FOLDL op r (a:x) => FOLDL op (op r a)^ x
-
- ^ (FOLDL op) is made strict in 1st param */
- getarg(arg1);
- getarg(arg2);
- upleft;
- while((lastarg=reduce(lastarg))!=NIL) /* ### */
- arg2=reduce(ap2(arg1,arg2,hd[lastarg])), /* ^ ### */
- lastarg=tl[lastarg];
- hd[e]=I, e=tl[e]=arg2;
- goto NEXTREDEX;
-
- case FOLDR: /* FOLDR op r [] => r
- FOLDR op r (a:x) => op a (FOLDR op r x) */
- getarg(arg1);
- getarg(arg2);
- upleft;
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==NIL)
- hd[e]=I, e=tl[e]=arg2;
- else hold=ap(hd[e],tl[lastarg]),
- hd[e]=ap(arg1,hd[lastarg]), tl[e]=hold;
- goto NEXTREDEX;
-
- L_READBIN:
- case READBIN: /* READBIN streamptr => nextchar : READBIN streamptr
- if end of file, READBIN file => NIL
- READBIN does no UTF-8 conversion */
- UPLEFT; /* gc insecurity - arg is not a heap object */
- if(lastarg==0) /* special case created by $:- */
- { if(stdinuse=='-')stdin_error(':');
- if(stdinuse)
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- stdinuse=':';
- tl[e]=(word)stdin; }
- hold= getc((FILE *)lastarg);
- if(hold==EOF)
- { fclose((FILE *)lastarg);
- hd[e]=I;
- e=tl[e]= NIL;
- goto DONE; }
- setcell(CONS,hold,ap(READBIN,lastarg));
- goto DONE;
-
- L_READ:
- case READ: /* READ streamptr => nextchar : READ streamptr
- if end of file, READ file => NIL
- does UTF-8 conversion where appropriate */
- UPLEFT; /* gc insecurity - arg is not a heap object */
- if(lastarg==0) /* special case created by $- */
- { if(stdinuse==':')stdin_error('-');
- if(stdinuse)
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- stdinuse='-';
- tl[e]=(word)stdin; }
- hold=UTF8?sto_char(fromUTF8((FILE *)lastarg)):getc((FILE *)lastarg);
- if(hold==EOF)
- { fclose((FILE *)lastarg);
- hd[e]=I;
- e=tl[e]= NIL;
- goto DONE; }
- setcell(CONS,hold,ap(READ,lastarg));
- goto DONE;
-
- L_READVALS:
- case READVALS: /* READVALS (t:fil) f => [], EOF from FILE *f
- => val : READVALS t f, otherwise
- where val is obtained by parsing lines of
- f, and taking next legal expr of type t */
- GETARG(arg1);
- upleft;
- hold=parseline(hd[arg1],(FILE *)lastarg,tl[arg1]);
- if(hold==EOF)
- { fclose((FILE *)lastarg);
- hd[e]=I;
- e=tl[e]= NIL;
- goto DONE; }
- arg2=ap(hd[e],lastarg);
- setcell(CONS,hold,arg2);
- goto DONE;
-
- case BADCASE: /* BADCASE cons(oldn,here_info) => BOTTOM */
- UPLEFT;
- { extern word sourcemc;
- word subject= hd[lastarg];
- /* either datapair(oldn,0) or 0 */
- fprintf(stderr,"\nprogram error: missing case in definition");
- if(subject) /* cannot do patterns - FIX LATER */
- fprintf(stderr," of %s",(char *)hd[subject]);
- putc('\n',stderr);
- out_here(stderr,tl[lastarg],1);
- /* if(sourcemc&&nargs>1)
- { int i=2;
- fprintf(stderr,"arg%s = ",nargs>2?"s":"");
- while(i<=nargs)out(stderr,tl[stackp[-(i++)]]),putc(' ',stderr);
- putc('\n',stderr); } /* fix later */
- }
- outstats();
- exit(1);
-
- case GETARGS: /* GETARGS 0 => argv ||`$*' = command line args */
- UPLEFT;
- simpl(conv_args());
- goto DONE;
-
- case CONFERROR: /* CONFERROR error_info => BOTTOM */
- /* if(nargs<1)fprintf(stderr,"\nimpossible event in reduce\n"),
- exit(1); */
- UPLEFT;
- fprintf(stderr,"\nprogram error: lhs of definition doesn't match rhs");
- /*fprintf(stderr," OF ");
- out_formal1(stderr,hd[lastarg]); /* omit - names may have been aliased */
- putc('\n',stderr);
- out_here(stderr,tl[lastarg],1);
- outstats();
- exit(1);
-
- case ERROR: /* ERROR error_info => BOTTOM */
- upleft;
- if(errtrap)fprintf(stderr,"\n(repeated error)\n");
- else { errtrap=1;
- fprintf(stderr,"\nprogram error: ");
- s_out=stderr;
- print(lastarg); /* ### */
- putc('\n',stderr); }
- outstats();
- exit(1);
-
- case WAIT: /* WAIT pid => <exit_status of child process pid> */
- UPLEFT;
- { word *w= &waiting; /* list of terminated pid's and their exit statuses */
- while(*w!=NIL&&hd[*w]!=lastarg)w= &tl[tl[*w]];
- if(*w!=NIL)hold=hd[tl[*w]],
- *w=tl[tl[*w]]; /* remove entry */
- else { word status;
- while((hold=wait(&status))!=lastarg&&hold!= -1)
- waiting=cons(hold,cons(WEXITSTATUS(status),waiting));
- if(hold!= -1)hold=WEXITSTATUS(status); }}
- simpl(stosmallint(hold));
- goto DONE;
-
- L_I:
-/* case MONOP: (all strict monadic operators share this code) */
- case I: /* we treat I as strict to avoid I-chains (MOD1) */
- case SEQ:
- case FORCE:
- case HD:
- case TL:
- case BODY:
- case LAST:
- case EXEC:
- case FILEMODE:
- case FILESTAT:
- case GETENV:
- case INTEGER:
- case NUMVAL:
- case TAKE:
- case STARTREAD:
- case STARTREADBIN:
- case NB_STARTREAD:
- case COND:
- case APPEND:
- case AND:
- case OR:
- case NOT:
- case NEG:
- case CODE:
- case DECODE:
- case SHOWNUM:
- case SHOWHEX:
- case SHOWOCT:
- case ARCTAN_FN: /* ...FN are strict functions of one numeric arg */
- case EXP_FN:
- case ENTIER_FN:
- case LOG_FN:
- case LOG10_FN:
- case SIN_FN:
- case COS_FN:
- case SQRT_FN:
- downright; /* subtask -- reduce arg */
- goto NEXTREDEX;
-
- case TRY: /* TRY f g x => TRY(f x)(g x) */
- getarg(arg1);
- getarg(arg2);
- while(!abnormal(s))
- { UPLEFT;
- hd[e]=ap(TRY,arg1=ap(arg1,lastarg));
- arg2=tl[e]=ap(arg2,lastarg); }
- DOWNLEFT;
- /* DOWNLEFT; DOWNRIGHT; equivalent to:*/
- hold=s,s=e,e=tl[e],tl[s]=hold,mktlptr(s); /* now be strict in arg1 */
- goto NEXTREDEX;
-
- case FAIL: /* FAIL x => FAIL */
- while(!abnormal(s))hold=s,s=hd[s],hd[hold]=FAIL,tl[hold]=0;
- goto DONE;
-
-/* case DIOP: (all strict diadic operators share this code) */
- case ZIP:
- case STEP:
- case EQ:
- case NEQ:
- case PLUS:
- case MINUS:
- case TIMES:
- case INTDIV:
- case FDIV:
- case MOD:
- case GRE:
- case GR:
- case POWER:
- case SHOWSCALED:
- case SHOWFLOAT:
- case MERGE:
- upleft;
- downright; /* first subtask -- reduce arg2 */
- goto NEXTREDEX;
-
- case Ush: /* strict in three args */
- case STEPUNTIL:
- upleft;
- upleft;
- downright;
- goto NEXTREDEX; /* first subtask -- reduce arg3 */
-
- case Ush1: /* non-strict version of Ush */
- /* Ush1 (k f1...fn) p stuff
- => "k"++' ':f1 x1 ...++' ':fn xn, p='\0'
- => "(k"++' ':f1 x1 ...++' ':fn xn++")", p='\1'
- where xi = LAST(BODY^(n-i) stuff) */
- getarg(arg1);
- arg1=reduce(arg1); /* ### */
- getarg(arg2);
- arg2=reduce(arg2); /* ### */
- getarg(arg3);
- if(tag[arg1]==CONSTRUCTOR) /* don't parenthesise atom */
- { hd[e]=I;
- if(suppressed(arg1))
- e=tl[e]=str_conv("<unprintable>");
- else e=tl[e]=str_conv(constr_name(arg1));
- goto DONE; }
- hold=arg2?cons(')',NIL):NIL;
- while(tag[arg1]!=CONSTRUCTOR)
- hold=cons(' ',ap2(APPEND,ap(tl[arg1],ap(LAST,arg3)),hold)),
- arg1=hd[arg1],arg3=ap(BODY,arg3);
- if(suppressed(arg1))
- { hd[e]=I; e=tl[e]=str_conv("<unprintable>"); goto DONE; }
- hold=ap2(APPEND,str_conv(constr_name(arg1)),hold);
- if(arg2)
- { setcell(CONS,'(',hold); goto DONE; }
- else { hd[e]=I; e=tl[e]=hold; goto NEXTREDEX; }
-
- case MKSTRICT: /* MKSTRICT k f x1 ... xk => f x1 ... xk, xk~=BOT */
- GETARG(arg1);
- getarg(arg2);
- { word i=arg1;
- while(i--) { upleft; } }
- lastarg=reduce(lastarg); /* ### */
- while(--arg1) /* go back towards head, copying spine */
- { hd[e]=ap(hd[hd[e]],tl[hd[e]]);
- DOWNLEFT;}
- hd[e]=arg2; /* overwrite (MKSTRICT k f) with f */
- goto NEXTREDEX;
-
- case G_ERROR: /* G_ERROR f g toks = (g residue):[], fails(f toks)
- = f toks, otherwise */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- hold=ap(arg1,lastarg);
- hold=reduce(hold); /* ### */
- if(!fails(hold))
- { hd[e]=I; e=tl[e]=hold; goto DONE; }
- hold=g_residue(lastarg);
- setcell(CONS,ap(arg2,hold),NIL);
- goto DONE;
-
- case G_ALT: /* G_ALT f g toks = f toks, !fails(f toks)
- = g toks, otherwise */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- hold=ap(arg1,lastarg);
- hold=reduce(hold); /* ### */
- if(!fails(hold))
- { hd[e]=I; e=tl[e]=hold; goto DONE; }
- hd[e]=arg2;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case G_OPT: /* G_OPT f toks = []:toks, fails(f toks)
- = [a]:toks', otherwise
- where
- a:toks' = f toks */
- GETARG(arg1);
- upleft;
- hold=ap(arg1,lastarg);
- hold=reduce(hold); /* ### */
- if(fails(hold))
- setcell(CONS,NIL,lastarg);
- else setcell(CONS,cons(hd[hold],NIL),tl[hold]);
- goto DONE;
-
- case G_STAR: /* G_STAR f toks => []:toks, fails(f toks)
- => ((a:FST z):SND z)
- where
- a:toks' = f toks
- z = G_STAR f toks'
- */
- GETARG(arg1);
- upleft;
- hold=ap(arg1,lastarg);
- hold=reduce(hold); /* ### */
- if(fails(hold))
- { setcell(CONS,NIL,lastarg); goto DONE; }
- arg2=ap(hd[e],tl[hold]); /* called z in above rules */
- tag[e]=CONS;hd[e]=cons(hd[hold],ap(FST,arg2));tl[e]=ap(SND,arg2);
- goto DONE;
-
- /* G_RULE has same action as P */
-
- case G_FBSTAR: /* G_FBSTAR f toks
- = I:toks, if fails(f toks)
- = G_SEQ (G_FBSTAR f) (G_RULE (CB a)) toks', otherwise
- where a:toks' = f toks
- */
- GETARG(arg1);
- upleft;
- hold=ap(arg1,lastarg);
- hold=reduce(hold); /* ### */
- if(fails(hold))
- { setcell(CONS,I,lastarg); goto DONE; }
- hd[e]=ap2(G_SEQ,hd[e],ap(G_RULE,ap(CB,hd[hold]))); tl[e]=tl[hold];
- goto NEXTREDEX;
-
- case G_SYMB: /* G_SYMB t ((t,s):toks) = t:toks
- G_SYMB t toks = FAILURE */
- GETARG(arg1); /* will be in NF */
- upleft;
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==NIL)
- { hd[e]=I,e=tl[e]=NIL; goto DONE; }
- hd[lastarg]=reduce(hd[lastarg]); /* ### */
- hold=ap(FST,hd[lastarg]);
- if(compare(arg1,reduce(hold))) /* ### */
- hd[e]=I,e=tl[e]=FAILURE;
- else setcell(CONS,arg1,tl[lastarg]);
- goto DONE;
-
- case G_ANY: /* G_ANY ((t,s):toks) = t:toks
- G_ANY [] = FAILURE */
- upleft;
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==NIL)
- hd[e]=I,e=tl[e]=FAILURE;
- else setcell(CONS,ap(FST,hd[lastarg]),tl[lastarg]);
- goto DONE;
-
- case G_SUCHTHAT: /* G_SUCHTHAT f ((t,s):toks) = t:toks, f t
- G_SUCHTHAT f toks = FAILURE */
- GETARG(arg1);
- upleft;
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==NIL)
- { hd[e]=I,e=tl[e]=FAILURE; goto DONE; }
- hold=ap(FST,hd[lastarg]);
- hold=reduce(hold); /* ### */
- if(reduce(ap(arg1,hold))==True) /* ### */
- setcell(CONS,hold,tl[lastarg]);
- else hd[e]=I,e=tl[e]=FAILURE;
- goto DONE;
-
-
- case G_END: /* G_END [] = []:[]
- G_END other = FAILURE */
- upleft;
- lastarg=reduce(lastarg);
- if(lastarg==NIL)
- setcell(CONS,NIL,NIL);
- else hd[e]=I,e=tl[e]=FAILURE;
- goto DONE;
-
- case G_STATE: /* G_STATE ((t,s):toks) = s:((t,s):toks)
- G_STATE [] = FAILURE */
- upleft;
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==NIL)
- hd[e]=I,e=tl[e]=FAILURE;
- else setcell(CONS,ap(SND,hd[lastarg]),lastarg);
- goto DONE;
-
- case G_SEQ: /* G_SEQ f g toks = FAILURE, fails(f toks)
- = FAILURE, fails(g toks')
- = b a:toks'', otherwise
- where
- a:toks' = f toks
- b:toks'' = g toks' */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- hold=ap(arg1,lastarg);
- hold=reduce(hold); /* ### */
- if(fails(hold))
- { hd[e]=I,e=tl[e]=FAILURE; goto DONE; }
- arg3=ap(arg2,tl[hold]);
- arg3=reduce(arg3); /* ### */
- if(fails(arg3))
- { hd[e]=I,e=tl[e]=FAILURE; goto DONE; }
- setcell(CONS,ap(hd[arg3],hd[hold]),tl[arg3]);
- goto DONE;
-
- case G_UNIT: /* G_UNIT toks => I:toks */
- upleft;
- tag[e]=CONS,hd[e]=I;
- goto DONE;
- /* G_UNIT is right multiplicative identity, equivalent (G_RULE I) */
-
- case G_ZERO: /* G_ZERO toks => FAILURE */
- upleft;
- simpl(FAILURE);
- goto DONE;
- /* G_ZERO is left additive identity */
-
- case G_CLOSE: /* G_CLOSE s f toks = <error s>, fails(f toks')
- = <error s>, toks'' ~= NIL
- = a, otherwise
- where
- toks' = G_COUNT toks
- a:toks'' = f toks' */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- arg3=ap(G_COUNT,lastarg);
- hold=ap(arg2,arg3);
- hold=reduce(hold); /* ### */
- if(fails(hold) /* ||(tl[hold]=reduce(tl[hold]))!=NIL /* ### */
- ) /* suppress to make parsers lazy by default 13/12/90 */
- { fprintf(stderr,"\nPARSE OF %sFAILS WITH UNEXPECTED ",
- getstring(arg1,0));
- arg3=reduce(tl[g_residue(arg3)]);
- if(arg3==NIL)
- fprintf(stderr,"END OF INPUT\n"),
- outstats(),
- exit(1);
- hold=ap(FST,hd[arg3]);
- hold=reduce(hold);
- fprintf(stderr,"TOKEN \"");
- if(hold==OFFSIDE)fprintf(stderr,"offside"); /* not now possible */
- { char *p=getstring(hold,0);
- while(*p)fprintf(stderr,"%s",charname(*p++)); }
- fprintf(stderr,"\"\n");
- outstats();
- exit(1); }
- hd[e]=I,e=tl[e]=hd[hold];
- goto NEXTREDEX;
-/* NOTE the atom OFFSIDE differs from every string and is used as a
- pseudotoken when implementing the offside rule - see `indent' in prelude */
-
- case G_COUNT: /* G_COUNT NIL => NIL
- G_COUNT (t:toks) => t:G_COUNT toks */
- /* G_COUNT is an identity operation on lists - its purpose is to mark
- last token examined, for syntax error location purposes */
- upleft;
- if((lastarg=reduce(lastarg))==NIL) /* ### */
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- setcell(CONS,hd[lastarg],ap(G_COUNT,tl[lastarg]));
- goto DONE;
-
-/* Explanation of %lex combinators. A lex analyser is of type
-
- lexer == [char] -> [alpha]
-
- At top level these are of the form (LEX_RPT f) where f is of type
-
- lexer1 == startcond -> [char] -> (alpha,startcond,[char])
-
- A lexer1 is guaranteed to return a triple (if it returns at all...)
- and is built using LEX_TRY.
-
- LEX_TRY [(scstuff,(matcher [],rule))*] :: lexer1
- rule :: [char] -> alpha
- matcher :: partial_match -> input -> {(alpha,input') | []}
-
- partial_match and input are both [char] and [] represents failure.
- The other lex combinators - LEX_SEQ, LEX_OR, LEX_CLASS etc., all
- create and combine objects of type matcher.
-
- LEX_RPT1 is a deviant version that labels the input characters
- with their lexical state (row,col) using LEX_COUNT - goes with
- LEX_TRY1 which feeds the leading state of input to each rule.
-
-*/
-
- case LEX_RPT1: /* LEX_RPT1 f s x => LEX_RPT f s (LEX_COUNT0 x)
- i.e. LEX_RPT1 f s => B (LEX_RPT f s) LEX_COUNT0
- */
- GETARG(arg1);
- UPLEFT;
- hd[e]=ap(B,ap2(LEX_RPT,arg1,lastarg)); tl[e]=LEX_COUNT0;
- DOWNLEFT;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case LEX_RPT: /* LEX_RPT f s [] => []
- LEX_RPT f s x => a : LEX_RPT f s' y
- where
- (a,s',y) = f s x
- note that if f returns a result it is
- guaranteed to be a triple
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- if((lastarg=reduce(lastarg))==NIL) /* ### */
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- hold=ap2(arg1,arg2,lastarg);
- arg1=hd[hd[e]];
- hold=reduce(hold);
- setcell(CONS,hd[hold],ap2(arg1,hd[tl[hold]],tl[tl[hold]]));
- goto DONE;
-
- case LEX_TRY:
- upleft;
- tl[e]=reduce(tl[e]); /* ### */
- force(tl[e]);
- hd[e]=LEX_TRY_;
- DOWNLEFT;
- /* falls thru to next case */
-
- case LEX_TRY_:
- /* LEX_TRY ((scstuff,(f,rule)):alt) s x => LEX_TRY alt s x, if f x = []
- => (rule (rev a),s,y), otherwise
- where
- (a,y) = f x
- LEX_TRY [] s x => BOTTOM
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
-L2: if(arg1==NIL)lexfail(lastarg);
- if(hd[hd[hd[arg1]]]&&!member(hd[hd[hd[arg1]]],arg2))
- { arg1=tl[arg1]; goto L2; } /* hd[scstuff] is 0 or list of startconds */
- hold=ap(hd[tl[hd[arg1]]],lastarg);
- if((hold=reduce(hold))==NIL) /* ### */
- { arg1=tl[arg1]; goto L2; }
- setcell(CONS,ap(tl[tl[hd[arg1]]],ap(DESTREV,hd[hold])),
- cons(tl[hd[hd[arg1]]]?tl[hd[hd[arg1]]]-1:arg2,tl[hold]));
- /* tl[scstuff] is 1 + next start condition (0 = no change) */
- goto DONE;
-
- case LEX_TRY1:
- upleft;
- tl[e]=reduce(tl[e]); /* ### */
- force(tl[e]);
- hd[e]=LEX_TRY1_;
- DOWNLEFT;
- /* falls thru to next case */
-
- case LEX_TRY1_:
- /* LEX_TRY1 ((scstuff,(f,rule)):alt) s x => LEX_TRY1 alt s x, if f x = []
- => (rule n (rev a),s,y), otherwise
- where
- (a,y) = f x
- n = lexstate(x)
- ||same as LEX_TRY but feeds lexstate to rule
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
-L3: if(arg1==NIL)lexfail(lastarg);
- if(hd[hd[hd[arg1]]]&&!member(hd[hd[hd[arg1]]],arg2))
- { arg1=tl[arg1]; goto L3; } /* hd[scstuff] is 0 or list of startconds */
- hold=ap(hd[tl[hd[arg1]]],lastarg);
- if((hold=reduce(hold))==NIL) /* ### */
- { arg1=tl[arg1]; goto L3; }
- setcell(CONS,ap2(tl[tl[hd[arg1]]],lexstate(lastarg),ap(DESTREV,hd[hold])),
- cons(tl[hd[hd[arg1]]]?tl[hd[hd[arg1]]]-1:arg2,tl[hold]));
- /* tl[scstuff] is 1 + next start condition (0 = no change) */
- goto DONE;
-
- case DESTREV: /* destructive reverse - used only by LEX_TRY */
- GETARG(arg1); /* known to be an explicit list */
- arg2=NIL; /* to hold reversed list */
- while(arg1!=NIL)
- { if(tag[hd[arg1]]==STRCONS) /* strip off lex state if present */
- hd[arg1]=tl[hd[arg1]];
- hold=tl[arg1],tl[arg1]=arg2,arg2=arg1,arg1=hold; }
- hd[e]=I; e=tl[e]=arg2;
- goto DONE;
-
- case LEX_COUNT0: /* LEX_COUNT0 x => LEX_COUNT (state0,x) */
- upleft;
- hd[e]=LEX_COUNT; tl[e]=strcons(0,tl[e]);
- DOWNLEFT;
- /* falls thru to next case */
-
- case LEX_COUNT: /* LEX_COUNT (state,[]) => []
- LEX_COUNT (state,(a:x)) => (state,a):LEX_COUNT(state',a)
- where
- state == (line_no*256+col_no)
- */
- GETARG(arg1);
- if((tl[arg1]=reduce(tl[arg1]))==NIL) /* ### */
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- hold=hd[tl[arg1]]; /* the char */
- setcell(CONS,strcons(hd[arg1],hold),ap(LEX_COUNT,arg1));
- if(hold=='\n')hd[arg1]=(hd[arg1]>>8)+1<<8;
- else { word col = hd[arg1]&255;
- col = hold=='\t'?(col/8+1)*8:col+1;
- hd[arg1] = hd[arg1]&(~255)|col; }
- tl[arg1]=tl[tl[arg1]];
- goto DONE;
-
-#define lh(x) (tag[hd[x]]==STRCONS?tl[hd[x]]:hd[x])
- /* hd char of possibly lex-state-labelled string */
-
- case LEX_STRING: /* LEX_STRING [] p x => p : x
- LEX_STRING (c:s) p (c:x) => LEX_STRING s (c:p) x
- LEX_STRING (c:s) p other => []
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- while(arg1!=NIL)
- { if((lastarg=reduce(lastarg))==NIL||lh(lastarg)!=hd[arg1]) /* ### */
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- arg1=tl[arg1]; arg2=cons(hd[lastarg],arg2); lastarg=tl[lastarg]; }
- tag[e]=CONS; hd[e]=arg2;
- goto DONE;
-
- case LEX_CLASS: /* LEX_CLASS set p (c:x) => (c:p) : x, if c in set
- LEX_CLASS set p x => [], otherwise
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- if((lastarg=reduce(lastarg))==NIL|| /* ### */
- (hd[arg1]==ANTICHARCLASS?memclass(lh(lastarg),tl[arg1])
- :!memclass(lh(lastarg),arg1))
- )
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- setcell(CONS,cons(hd[lastarg],arg2),tl[lastarg]);
- goto DONE;
-
- case LEX_DOT: /* LEX_DOT p (c:x) => (c:p) : x
- LEX_DOT p [] => []
- */
- GETARG(arg1);
- upleft;
- if((lastarg=reduce(lastarg))==NIL) /* ### */
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- setcell(CONS,cons(hd[lastarg],arg1),tl[lastarg]);
- goto DONE;
-
- case LEX_CHAR: /* LEX_CHAR c p (c:x) => (c:p) : x
- LEX_CHAR c p x => []
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- if((lastarg=reduce(lastarg))==NIL||lh(lastarg)!=arg1) /* ### */
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- setcell(CONS,cons(arg1,arg2),tl[lastarg]);
- goto DONE;
-
- case LEX_SEQ: /* LEX_SEQ f g p x => [], if f p x = []
- => g q y, otherwise
- where
- (q,y) = f p x
- */
- GETARG(arg1);
- GETARG(arg2);
- GETARG(arg3);
- upleft;
- hold=ap2(arg1,arg3,lastarg);
- lastarg=NIL; /* anti-dragging measure */
- if((hold=reduce(hold))==NIL) /* ### */
- { hd[e]=I; e=tl[e]; goto DONE; }
- hd[e]=ap(arg2,hd[hold]); tl[e]=tl[hold];
- DOWNLEFT;
- DOWNLEFT;
- goto NEXTREDEX;
-
- case LEX_OR: /* LEX_OR f g p x => g p x, if f p x = []
- => f p x, otherwise
- */
- GETARG(arg1);
- GETARG(arg2);
- GETARG(arg3);
- upleft;
- hold=ap2(arg1,arg3,lastarg);
- if((hold=reduce(hold))==NIL) /* ### */
- { hd[e]=ap(arg2,arg3); DOWNLEFT; DOWNLEFT; goto NEXTREDEX; }
- hd[e]=I; e=tl[e]=hold;
- goto DONE;
-
- case LEX_RCONTEXT: /* LEX_RC f g p x => [], if f p x = []
- => [], if g q y = []
- => f p x, otherwise <-*
- where
- (q,y) = f p x
-
- (*) special case g=0 means test for y=[]
- */
- GETARG(arg1);
- GETARG(arg2);
- GETARG(arg3);
- upleft;
- hold=ap2(arg1,arg3,lastarg);
- lastarg=NIL; /* anti-dragging measure */
- if((hold=reduce(hold))==NIL /* ### */
- || (arg2?(reduce(ap2(arg2,hd[hold],tl[hold]))==NIL) /* ### */
- :(tl[hold]=reduce(tl[hold]))!=NIL ))
- { hd[e]=I; e=tl[e]; goto DONE; }
- hd[e]=I; e=tl[e]=hold;
- goto DONE;
-
- case LEX_STAR: /* LEX_STAR f p x => p : x, if f p x = []
- => LEX_STAR f q y, otherwise
- where
- (q,y) = f p x
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- hold=ap2(arg1,arg2,lastarg);
- while((hold=reduce(hold))!=NIL) /* ### */
- arg2=hd[hold],lastarg=tl[hold],hold=ap2(arg1,arg2,lastarg);
- tag[e]=CONS; hd[e]=arg2;
- goto DONE;
-
- case LEX_OPT: /* LEX_OPT f p x => p : x, if f p x = []
- => f p x, otherwise
- */
- GETARG(arg1);
- GETARG(arg2);
- upleft;
- hold=ap2(arg1,arg2,lastarg);
- if((hold=reduce(hold))==NIL) /* ### */
- { tag[e]=CONS; hd[e]=arg2; goto DONE; }
- hd[e]=I; e=tl[e]=hold;
- goto DONE;
-
-/* case NUMBER: /* constructor of arity 1
- UPLEFT; /* cannot occur free
- goto DONE; */ /* UNUSED*/
-
-/* case CONSTRUCTOR:
- for(;;){upleft; } /* reapply to args until DONE */
-
- default: /* non combinator */
- cycles--; /* oops! */
- if(abnormal(e)) /* silly recursion */
- { fprintf(stderr,"\nBLACK HOLE\n");
- outstats();
- exit(1); }
-
- switch(tag[e])
- { case STRCONS: e=pn_val(e); /* private name */
- /*if(e==UNDEF||e==FREE)
- fprintf(stderr,
- "\nimpossible event in reduce - undefined pname\n"),
- exit(1);
- /* redundant test - remove when sure */
- goto NEXTREDEX;
- case DATAPAIR: /* datapair(oldn,0)(fileinfo(filename,0))=>BOTTOM */
- /* kludge for trapping inherited undefined name without
- current alias - see code in load_defs */
- upleft;
- fprintf(stderr,
- "\nUNDEFINED NAME (specified as \"%s\" in %s)\n",
- (char *)hd[hd[e]],(char *)hd[lastarg]);
- outstats();
- exit(1);
- case ID: if(id_val(e)==UNDEF||id_val(e)==FREE)
- { fprintf(stderr,"\nUNDEFINED NAME - %s\n",get_id(e));
- outstats();
- exit(1); }
- /* setcell(AP,I,id_val(e)); /* overwrites error-info */
- e=id_val(e); /* could be eager in value */
- goto NEXTREDEX;
- default: fprintf(stderr,"\nimpossible tag (%d) in reduce\n",tag[e]);
- exit(1);
- case CONSTRUCTOR: for(;;){upleft; } /* reapply to args until DONE */
- case STARTREADVALS:
- /* readvals(0,t) file => READVALS (t:file) streamptr */
- { char *fil;
- upleft;
- lastarg=reduce(lastarg); /* ### */
- if(lastarg==OFFSIDE) /* special case, represents stdin */
- { if(stdinuse&&stdinuse!='+')
- { tag[e]=AP; hd[e]=I; e=tl[e]=NIL; goto DONE; }
- stdinuse='+';
- hold=cons(tl[hd[e]],0),lastarg=(word)stdin; }
- else
- hold=cons(tl[hd[e]],lastarg),
- lastarg=(word)fopen(fil=getstring(lastarg,"readvals"),"r");
- if((FILE *)lastarg==NULL) /* cannot open file for reading */
- /* { hd[e]=I; e=tl[e]=NIL; goto DONE; } */
- { fprintf(stderr,"\nreadvals, cannot open: \"%s\"\n",fil);
- outstats(); exit(1); }
- hd[e]=ap(READVALS,hold); }
- DOWNLEFT;
- DOWNLEFT;
- goto L_READVALS;
- case ATOM: /* for(;;){upleft; } */
- /* as above if there are constructors with tag ATOM
- and +ve arity. Since there are none we could test
- for missing combinators at this point. Thus
- /*if(!abnormal(s))
- fprintf(stderr,"\nreduce: unknown combinator "),
- out(stderr,e), putc('\n',stderr),exit(1); */
- case INT:
- case UNICODE:
- case DOUBLE:
- case CONS:; /* all fall thru to DONE */
- }
-
- } /* end of decode switch */
-
- DONE: /* sub task completed -- s is either BACKSTOP or a tailpointer */
-
- if(s==BACKSTOP)
- { /* whole expression now in hnf */
-#ifdef DEBUG
- if(debug&02)printf("result= "),out(stdout,e),putchar('\n');
- rdepth--;
-#endif
- return(e); /* end of reduction */
- /* outchar(hd[e]);
- e=tl[e];
- goto NEXTREDEX;
- /* above shows how to incorporate printing into m/c */
- }
-
- /* otherwise deal with return from subtask */
- UPRIGHT;
- if(tag[e]==AP)
- { /* we have just reduced argn of strict operator -- so now
- we must reduce arg(n-1) */
- DOWNLEFT;
- DOWNRIGHT; /* there is a faster way to do this - see TRY */
- goto NEXTREDEX;
- }
-
- /* only possible if mktlptr marks the cell rather than the field */
-/* if(e==BACKSTOP)
- fprintf(stderr,"\nprogram error: BLACK HOLE2\n"),
- outstats(),
- exit(1); */
-
- /* we are through reducing args of strict operator */
- /* we can merge the following switch with the main one, if desired,
- - in this case use the alternate definitions of READY and RESTORE
- and replace the following switch by
- /* e=READY(e); goto OPDECODE; */
-
-#ifdef DEBUG
- if(debug&02){ printf("ready("); out(stdout,e); printf(")\n"); }
-#endif
- switch(e) /* "ready" switch */
- {
-/* case READY(MONOP):/* paradigm for execution of strict monadic operator
- GETARG(arg1);
- hd[e]=I; e=tl[e]=do_monop(arg1);
- goto NEXTREDEX; */
-
- case READY(I): /* I x => x */
- UPLEFT;
- e=lastarg;
- goto NEXTREDEX;
-
- case READY(SEQ): /* SEQ a b => b, a~=BOTTOM */
- UPLEFT;
- upleft;
- hd[e]=I;e=lastarg;
- goto NEXTREDEX;
-
- case READY(FORCE): /* FORCE x => x, total x */
- UPLEFT;
- force(lastarg);
- hd[e]=I;e=lastarg;
- goto NEXTREDEX;
-
- case READY(HD):
- UPLEFT;
- if(lastarg==NIL)
- { fprintf(stderr,"\nATTEMPT TO TAKE hd OF []\n");
- outstats(); exit(1); }
- hd[e]=I; e=tl[e]=hd[lastarg];
- goto NEXTREDEX;
-
- case READY(TL):
- UPLEFT;
- if(lastarg==NIL)
- { fprintf(stderr,"\nATTEMPT TO TAKE tl OF []\n");
- outstats(); exit(1); }
- hd[e]=I; e=tl[e]=tl[lastarg];
- goto NEXTREDEX;
-
- case READY(BODY):
- /* BODY(k x1 .. xn) => k x1 ... x(n-1)
- for arbitrary constructor k */
- UPLEFT;
- hd[e]=I; e=tl[e]=hd[lastarg];
- goto NEXTREDEX;
-
- case READY(LAST): /* LAST(k x1 .. xn) => xn
- for arbitrary constructor k */
- UPLEFT;
- hd[e]=I; e=tl[e]=tl[lastarg];
- goto NEXTREDEX;
-
- case READY(TAKE):
- GETARG(arg1);
- upleft;
- if(tag[arg1]!=INT)word_error("take");
- { long long n=get_word(arg1);
- if(n<=0||(lastarg=reduce(lastarg))==NIL) /* ### */
- { simpl(NIL); goto DONE; }
- setcell(CONS,hd[lastarg],ap2(TAKE,sto_word(n-1),tl[lastarg])); }
- goto DONE;
-
- case READY(FILEMODE): /* FILEMODE string => string'
- (see filemode in manual) */
- UPLEFT;
- if(!stat(getstring(lastarg,"filemode"),&buf))
- { mode_t mode=buf.st_mode;
- word d=S_ISDIR(mode)?'d':'-';
- word perm= buf.st_uid==geteuid()?(mode&0700)>>6:
- buf.st_gid==getegid()?(mode&070)>>3:
- mode&07;
- word r=perm&04?'r':'-',w=perm&02?'w':'-',x=perm&01?'x':'-';
- setcell(CONS,d,cons(r,cons(w,cons(x,NIL))));
- }
- else hd[e]=I,e=tl[e]=NIL;
- goto DONE;
-
- case READY(FILESTAT): /* FILESTAT string => ((inode,dev),mtime) */
- UPLEFT;
- /* Notes:
- Non-existent file has conventional ((inode,dev),mtime) of ((0,-1),0)
- We assume time_t can be stored in int field, this may not port */
- if(!stat(getstring(lastarg,"filestat"),&buf))
- setcell(CONS,cons(sto_word(buf.st_ino),
- sto_word(buf.st_dev) ),
- sto_word(buf.st_mtime) );
- else setcell(CONS,cons(stosmallint(0),
- stosmallint(-1) ),
- stosmallint(0) );
- goto DONE;
-
- case READY(GETENV): /* GETENV string => string'
- (see man (2) getenv) */
- UPLEFT;
- { char *a = getstring(lastarg,"getenv");
- unsigned char *p = getenv(a);
- hold = NIL;
- if(p){ word i;
- unsigned char *q=p, *r=p;
- if(UTF8)
- { while(*r) /* compress to Latin-1 in situ */
- if(*r>127) /* start of multibyte */
- if((*r==194||*r==195)&&r[1]>=128&&r[1]<=191) /* Latin-1 */
- *q= *r==194?r[1]:r[1]+64, q++, r+=2;
- else getenv_error(a),
- /* or silently accept errors here? */
- *q++=*r++;
- else *q++=*r++;
- *q='\0';
- }
- /* convert p to list */
- i = strlen(p);
- while(i--)hold=cons(p[i],hold);
- }
- }
- hd[e]=I; e=tl[e]=hold;
- goto DONE;
-
- case READY(EXEC): /* EXEC string
- fork off a process to execute string as a
- shell command, returning (via pipes) the
- triple (stdout,stderr,exit_status)
- convention: if fork fails, exit status is -1 */
- UPLEFT;
- { word pid=(-1),fd[2],fd_a[2];
- char *cp=getstring(lastarg,"system");
- /* pipe(fd) should return 0, -1 means fail */
- /* fd_a is 2nd pipe, for error messages */
- if(pipe(fd)==(-1)||pipe(fd_a)==(-1)||(pid=fork()))
- { /* parent (reader) */
- FILE *fp,*fp_a;
- if(pid!= -1)
- close(fd[1]),
- close(fd_a[1]),
- fp=(FILE *)fdopen(fd[0],"r"),
- fp_a=(FILE *)fdopen(fd_a[0],"r");
- if(pid== -1||!fp||!fp_a)
- setcell(CONS,NIL,cons(piperrmess(pid),sto_word(-1))); else
- setcell(CONS,ap(READ,fp),cons(ap(READ,fp_a),ap(WAIT,pid)));
- }
- else { /* child (writer) */
- word in;
- static char *shell="/bin/sh";
- dup2(fd[1],1); /* so pipe replaces stdout */
- dup2(fd_a[1],2); /* 2nd pipe replaces stderr */
- close(fd[1]);
- close(fd[0]);
- close(fd_a[1]);
- close(fd_a[0]);
- fclose(stdin); /* anti side-effect measure */
- execl(shell,shell,"-c",cp,(char *)0);
- }
- }
- goto DONE;
-
- case READY(NUMVAL): /* NUMVAL numeral => number */
- UPLEFT;
- { word x=lastarg;
- word base=10;
- while(x!=NIL)
- hd[x]=reduce(hd[x]), /* ### */
- x=tl[x]=reduce(tl[x]); /* ### */
- while(lastarg!=NIL&&isspace(hd[lastarg]))lastarg=tl[lastarg];
- x=lastarg;
- if(x!=NIL&&hd[x]=='-')x=tl[x];
- if(hd[x]=='0'&&tl[x]!=NIL)
- switch(tolower(hd[tl[x]]))
- { case 'o':
- base=8;
- x=tl[tl[x]];
- while(x!=NIL&&isodigit(hd[x]))x=tl[x];
- break;
- case 'x':
- base=16;
- x=tl[tl[x]];
- while(x!=NIL&&isxdigit(hd[x]))x=tl[x];
- break;
- default: goto L;
- }
- else L: while(x!=NIL&&isdigit(hd[x]))x=tl[x];
- if(x==NIL)
- hd[e]=I,e=tl[e]=strtobig(lastarg,base);
- else { char *p=linebuf;
- double d; char junk=0;
- x=lastarg;
- while(x!=NIL&&p-linebuf<BUFSIZE-1) *p++ = hd[x], x=tl[x];
- *p++ ='\0';
- if(p-linebuf>60||sscanf(linebuf,"%lf%c",&d,&junk)!=1||junk)
- { fprintf(stderr,"\nbad arg for numval: \"%s\"\n",linebuf);
- outstats();
- exit(1); }
- else hd[e]=I,e=tl[e]=sto_dbl(d); }
- goto DONE; }
-
- case READY(STARTREAD): /* STARTREAD filename => READ streamptr */
- UPLEFT;
- { char *fil;
- lastarg = (word)fopen(fil=getstring(lastarg,"read"),"r");
- if((FILE *)lastarg==NULL) /* cannot open file for reading */
- /* { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- /* could just return empty contents */
- { fprintf(stderr,"\nread, cannot open: \"%s\"\n",fil);
- outstats(); exit(1); }
- hd[e]=READ;
- DOWNLEFT; }
- goto L_READ;
-
- case READY(STARTREADBIN): /* STARTREADBIN filename => READBIN streamptr */
- UPLEFT;
- { char *fil;
- lastarg = (word)fopen(fil=getstring(lastarg,"readb"),"r");
- if((FILE *)lastarg==NULL) /* cannot open file for reading */
- /* { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- /* could just return empty contents */
- { fprintf(stderr,"\nreadb, cannot open: \"%s\"\n",fil);
- outstats(); exit(1); }
- hd[e]=READBIN;
- DOWNLEFT; }
- goto L_READBIN;
-
- case READY(TRY): /* TRY FAIL y => y
- TRY other y => other */
- GETARG(arg1);
- UPLEFT;
- if(arg1==FAIL)
- { hd[e]=I; e=lastarg; goto NEXTREDEX; }
- if(S<=(hold=head(arg1))&&hold<=ERROR)
- /* function - other than unsaturated constructor */
- goto DONE;/* nb! else may take premature decision(interacts with MOD1)*/
- hd[e]=I;
- e=tl[e]=arg1;
- goto NEXTREDEX;
-
- case READY(COND): /* COND True => K
- COND False => KI */
- UPLEFT;
- hd[e]=I;
- if(lastarg==True)
- { e=tl[e]=K; goto L_K; }
- else { e=tl[e]=KI; goto L_KI; }
- /* goto OPDECODE; /* to speed up we have set extra labels */
-
- /* alternative rules /* COND True x => K x
- COND False x => I */
-
- case READY(APPEND): /* APPEND NIL y => y
- APPEND (a:x) y => a:APPEND x y */
- GETARG(arg1);
- upleft;
- if(arg1==NIL)
- { hd[e]=I,e=lastarg; goto NEXTREDEX; }
- setcell(CONS,hd[arg1],ap2(APPEND,tl[arg1],lastarg));
- goto DONE;
-
- case READY(AND): /* AND True => I
- AND False => K False */
- UPLEFT;
- if(lastarg==True){ e=I; goto L_I; }
- else { hd[e]=K,DOWNLEFT; goto L_K; }
-
- case READY(OR): /* OR True => K True
- OR False => I */
- UPLEFT;
- if(lastarg==True){ hd[e]=K; DOWNLEFT; goto L_K; }
- else { e=I; goto L_I; }
-
- /* alternative rules ?? /* AND True y => y
- AND False y => False
- OR True y => True
- OR False y => y */
-
- case READY(NOT): /* NOT True => False
- NOT False => True */
- UPLEFT;
- hd[e]=I; e=tl[e]=lastarg==True?False:True;
- goto DONE;
-
- case READY(NEG): /* NEG x => -x, if x is a number */
- UPLEFT;
- if(tag[lastarg]==INT)simpl(bignegate(lastarg));
- else setdbl(e,-get_dbl(lastarg));
- goto DONE;
-
- case READY(CODE): /* miranda char to int type-conversion */
- UPLEFT;
- simpl(make(INT,get_char(lastarg),0));
- goto DONE;
-
- case READY(DECODE): /* int to char type conversion */
- UPLEFT;
- if(tag[lastarg]==DOUBLE)word_error("decode");
- long long val=get_word(lastarg);
- if(val<0||val>UMAX)
- { fprintf(stderr,"\nCHARACTER OUT-OF-RANGE decode(%d)\n",val);
- outstats();
- exit(1); }
- hd[e]=I; e=tl[e]=sto_char(val);
- goto DONE;
-
- case READY(INTEGER): /* predicate on numbers */
- UPLEFT;
- hd[e]=I; e=tl[e]=tag[lastarg]==INT?True:False;
- goto NEXTREDEX;
-
- case READY(SHOWNUM): /* SHOWNUM number => numeral */
- UPLEFT;
- if(tag[lastarg]==DOUBLE)
- { double x=get_dbl(lastarg);
-#ifndef RYU
- sprintf(linebuf,"%.16g",x);
- char *p=linebuf;
- while isdigit(*p)p++; /* add .0 to false integer */
- if(!*p)*p++='.',*p++='0',*p='\0';
- hd[e]=I; e=tl[e]=str_conv(linebuf); }
-#else
- d2s_buffered(x,linebuf);
- arg1=str_conv(linebuf);
- if(*linebuf=='.')arg1=cons('0',arg1);
- if(*linebuf=='-'&&linebuf[1]=='.')arg1=cons('-',cons('0',tl[arg1]));
- hd[e]=I; e=tl[e]=arg1; }
-#endif
- else simpl(bigtostr(lastarg));
- goto DONE;
-
- case READY(SHOWHEX):
- UPLEFT;
- if(tag[lastarg]==DOUBLE)
- { sprintf(linebuf,"%a",get_dbl(lastarg));
- hd[e]=I; e=tl[e]=str_conv(linebuf); }
- else simpl(bigtostrx(lastarg));
- goto DONE;
-
- case READY(SHOWOCT):
- UPLEFT;
- if(tag[lastarg]==DOUBLE)word_error("showoct");
- else simpl(bigtostr8(lastarg));
- goto DONE;
-
- /* paradigm for strict monadic arithmetic fns */
- case READY(ARCTAN_FN): /* atan */
- UPLEFT;
- errno=0; /* to clear */
- setdbl(e,atan(force_dbl(lastarg)));
- if(errno)math_error("atan");
- goto DONE;
-
- case READY(EXP_FN): /* exp */
- UPLEFT;
- errno=0; /* to clear */
- setdbl(e,exp(force_dbl(lastarg)));
- if(errno)math_error("exp");
- goto DONE;
-
- case READY(ENTIER_FN): /* floor */
- UPLEFT;
- if(tag[lastarg]==INT)simpl(lastarg);
- else simpl(dbltobig(get_dbl(lastarg)));
- goto DONE;
-
- case READY(LOG_FN): /* log */
- UPLEFT;
- if(tag[lastarg]==INT)setdbl(e,biglog(lastarg));
- else { errno=0; /* to clear */
- fa=force_dbl(lastarg);
- setdbl(e,log(fa));
- if(errno)math_error("log"); }
- goto DONE;
-
- case READY(LOG10_FN): /* log10 */
- UPLEFT;
- if(tag[lastarg]==INT)setdbl(e,biglog10(lastarg));
- else { errno=0; /* to clear */
- fa=force_dbl(lastarg);
- setdbl(e,log10(fa));
- if(errno)math_error("log10"); }
- goto DONE;
-
- case READY(SIN_FN): /* sin */
- UPLEFT;
- errno=0; /* to clear */
- setdbl(e,sin(force_dbl(lastarg)));
- if(errno)math_error("sin");
- goto DONE;
-
- case READY(COS_FN): /* cos */
- UPLEFT;
- errno=0; /* to clear */
- setdbl(e,cos(force_dbl(lastarg)));
- if(errno)math_error("cos");
- goto DONE;
-
- case READY(SQRT_FN): /* sqrt */
- UPLEFT;
- fa=force_dbl(lastarg);
- if(fa<0.0)math_error("sqrt");
- setdbl(e,sqrt(fa));
- goto DONE;
-
-/* case READY(DIOP):/* paradigm for execution of strict diadic operator
- RESTORE(e); /* do not write modified form of operator back into graph
- GETARG(arg1);
- GETARG(arg2);
- hd[e]=I; e=tl[e]=diop(arg1,arg2);
- goto NEXTREDEX; */
-
-/* case READY(EQUAL): /* UNUSED
- RESTORE(e);
- GETARG(arg1);
- GETARG(arg2);
- if(isap(arg1)&&hd[arg1]!=NUMBER&&isap(arg2)&&hd[arg2]!=NUMBER)
- { /* recurse on components
- hd[e]=ap2(EQUAL,tl[arg1],tl[arg2]);
- hd[e]=ap3(EQUAL,hd[arg1],hd[arg2],hd[e]);
- tl[e]=False;
- }
- else { hd[e]=I; e=tl[e]= (eqatom(arg1,arg2)?True:False); }
- goto NEXTREDEX; */
-
- case READY(ZIP): /* ZIP (a:x) (b:y) => (a,b) : ZIP x y
- ZIP x y => [] */
- RESTORE(e);
- GETARG(arg1);
- GETARG(arg2);
- if(arg1==NIL||arg2==NIL)
- { hd[e]=I; e=tl[e]=NIL; goto DONE; }
- setcell(CONS,cons(hd[arg1],hd[arg2]),ap2(ZIP,tl[arg1],tl[arg2]));
- goto DONE;
-
- case READY(EQ): /* EQ x x => True
- EQ x y => False
- see definition of function "compare" above */
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- hd[e]=I; e=tl[e]=compare(arg1,lastarg)?False:True; /* ### */
- goto DONE;
-
- case READY(NEQ): /* NEQ x x => False
- NEQ x y => True
- see definition of function "compare" above */
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- hd[e]=I; e=tl[e]=compare(arg1,lastarg)?True:False; /* ### */
- goto DONE;
-
- case READY(GR):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- hd[e]=I; e=tl[e]=compare(arg1,lastarg)>0?True:False; /* ### */
- goto DONE;
-
- case READY(GRE):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- hd[e]=I; e=tl[e]=compare(arg1,lastarg)>=0?True:False; /* ### */
- goto DONE;
-
- case READY(PLUS):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[arg1]==DOUBLE)
- setdbl(e,get_dbl(arg1)+force_dbl(lastarg)); else
- if(tag[lastarg]==DOUBLE)
- setdbl(e,bigtodbl(arg1)+get_dbl(lastarg));
- else simpl(bigplus(arg1,lastarg));
- goto DONE;
-
- case READY(MINUS):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[arg1]==DOUBLE)
- setdbl(e,get_dbl(arg1)-force_dbl(lastarg)); else
- if(tag[lastarg]==DOUBLE)
- setdbl(e,bigtodbl(arg1)-get_dbl(lastarg));
- else simpl(bigsub(arg1,lastarg));
- goto DONE;
-
- case READY(TIMES):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[arg1]==DOUBLE)
- setdbl(e,get_dbl(arg1)*force_dbl(lastarg)); else
- if(tag[lastarg]==DOUBLE)
- setdbl(e,bigtodbl(arg1)*get_dbl(lastarg));
- else simpl(bigtimes(arg1,lastarg));
- goto DONE;
-
- case READY(INTDIV):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[arg1]==DOUBLE||tag[lastarg]==DOUBLE)word_error("div");
- if(bigzero(lastarg))div_error(); /* build into bigmod ? */
- simpl(bigdiv(arg1,lastarg));
- goto DONE;
-
- case READY(FDIV):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- /* experiment, suppressed
- if(tag[lastarg]==INT&&tag[arg1]==INT&&!bigzero(lastarg))
- { extern int b_rem;
- int d = bigdiv(arg1,lastarg);
- if(bigzero(b_rem)){ simpl(d); goto DONE; }
- } /* makes a/b integer if a, b integers dividing exactly */
- fa=force_dbl(arg1);
- fb=force_dbl(lastarg);
- if(fb==0.0)div_error();
- setdbl(e,fa/fb);
- goto DONE;
-
- case READY(MOD):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[arg1]==DOUBLE||tag[lastarg]==DOUBLE)word_error("mod");
- if(bigzero(lastarg))div_error(); /* build into bigmod ? */
- simpl(bigmod(arg1,lastarg));
- goto DONE;
-
- case READY(POWER):
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[lastarg]==DOUBLE)
- { fa=force_dbl(arg1);
- if(fa<0.0)errno=EDOM,math_error("^");
- fb=get_dbl(lastarg); }else
- if(tag[arg1]==DOUBLE)
- fa=get_dbl(arg1),fb=bigtodbl(lastarg); else
- if(neg(lastarg))
- fa=bigtodbl(arg1),fb=bigtodbl(lastarg);
- else { simpl(bigpow(arg1,lastarg));
- goto DONE; }
- errno=0; /* to clear */
- setdbl(e,pow(fa,fb));
- if(errno)math_error("power");
- goto DONE;
-
- case READY(SHOWSCALED): /* SHOWSCALED precision number => numeral */
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[arg1]==DOUBLE)
- word_error("showscaled");
- arg1=getsmallint(arg1);
- (void)sprintf(linebuf,"%.*e",arg1,force_dbl(lastarg));
- hd[e]=I; e=tl[e]=str_conv(linebuf);
- goto DONE;
-
- case READY(SHOWFLOAT): /* SHOWFLOAT precision number => numeral */
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(tag[arg1]==DOUBLE)
- word_error("showfloat");
- arg1=getsmallint(arg1);
- (void)sprintf(linebuf,"%.*f",arg1,force_dbl(lastarg));
- hd[e]=I; e=tl[e]=str_conv(linebuf);
- goto DONE;
-
-#define coerce_dbl(x) tag[x]==DOUBLE?(x):sto_dbl(bigtodbl(x))
-
- case READY(STEP): /* STEP i a => GENSEQ (i,NIL) a */
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- hd[e]=ap(GENSEQ,cons(arg1,NIL));
- goto NEXTREDEX;
-
- case READY(MERGE): /* MERGE [] y => y
- MERGE (a:x) [] => a:x
- MERGE (a:x) (b:y) => a:MERGE x (b:y), if a<=b
- => b:MERGE (a:x) y, otherwise */
- RESTORE(e);
- GETARG(arg1);
- UPLEFT;
- if(arg1==NIL)simpl(lastarg); else
- if(lastarg==NIL)simpl(arg1); else
- if(compare(hd[arg1]=reduce(hd[arg1]),
- hd[lastarg]=reduce(hd[lastarg]))<=0) /* ### */
- setcell(CONS,hd[arg1],ap2(MERGE,tl[arg1],lastarg));
- else setcell(CONS,hd[lastarg],ap2(MERGE,tl[lastarg],arg1));
- goto DONE;
-
- case READY(STEPUNTIL): /* STEPUNTIL i a b => GENSEQ (i,b) a */
- RESTORE(e);
- GETARG(arg1);
- GETARG(arg2);
- UPLEFT;
- hd[e]=ap(GENSEQ,cons(arg1,arg2));
- if(tag[arg1]==INT?poz(arg1):get_dbl(arg1)>=0.0)
- tag[tl[hd[e]]]=AP; /* hack to record sign of step - see GENSEQ */
- goto NEXTREDEX;
-
- case READY(Ush):
- /* Ush (k f1...fn) p (k x1...xn)
- => "k"++' ':f1 x1 ...++' ':fn xn, p='\0'
- => "(k"++' ':f1 x1 ...++' ':fn xn++")", p='\1'
- Ush (k f1...fn) p other => FAIL */
- RESTORE(e);
- GETARG(arg1);
- GETARG(arg2);
- GETARG(arg3);
- if(constr_tag(head(arg1))!=constr_tag(head(arg3)))
- { hd[e]=I;
- e=tl[e]=FAIL;
- goto DONE; } /* result is string, so cannot be more args */
- if(tag[arg1]==CONSTRUCTOR) /* don't parenthesise atom */
- { hd[e]=I;
- if(suppressed(arg1))
- e=tl[e]=str_conv("<unprintable>");
- else e=tl[e]=str_conv(constr_name(arg1));
- goto DONE; }
- hold=arg2?cons(')',NIL):NIL;
- while(tag[arg1]!=CONSTRUCTOR)
- hold=cons(' ',ap2(APPEND,ap(tl[arg1],tl[arg3]),hold)),
- arg1=hd[arg1],arg3=hd[arg3];
- if(suppressed(arg1))
- { hd[e]=I; e=tl[e]=str_conv("<unprintable>"); goto DONE; }
- hold=ap2(APPEND,str_conv(constr_name(arg1)),hold);
- if(arg2)
- { setcell(CONS,'(',hold); goto DONE; }
- else { hd[e]=I; e=tl[e]=hold; goto NEXTREDEX; }
-
- default: fprintf(stderr,"\nimpossible event in reduce ("),
- out(stderr,e),fprintf(stderr,")\n"),
- exit(1);
- return(0); /* proforma only - unreachable */
- } /* end of "ready" switch */
-
-} /* end of reduce */
-
-memclass(c,x) /* is char c in list x (may include ranges) */
-{ while(x!=NIL)
- { if(hd[x]==DOTDOT)
- { x=tl[x];
- if(hd[x]<=c&&c<=hd[tl[x]])return(1);
- x=tl[x]; }
- else if(c==hd[x])return(1);
- x=tl[x]; }
- return(0);
-}
-
-lexfail(x) /* x is known to be a non-empty string (see LEX_RPT) */
-{ word i=24;
- fprintf(stderr,"\nLEX FAILS WITH UNRECOGNISED INPUT: \"");
- while(i--&&x!=NIL&&0<=lh(x)&&lh(x)<=255)
- fprintf(stderr,"%s",charname(lh(x))),
- x=tl[x];
- fprintf(stderr,"%s\"\n",x==NIL?"":"...");
- outstats();
- exit(1);
-}
-
-lexstate(x) /* extracts initial state info from list of chars labelled
- by LEX_COUNT - x is evaluated and known to be non-empty */
-{ x = hd[hd[x]]; /* count field of first char */
- return(cons(sto_word(x>>8),stosmallint(x&255)));
-}
-
-piperrmess(pid)
-word pid;
-{ return(str_conv(pid== -1?"cannot create process\n":"cannot open pipe\n"));
-}
-
-g_residue(toks2) /* remainder of token stream from last token examined */
-word toks2;
-{ word toks1 = NIL;
- if(tag[toks2]!=CONS)
- { if(tag[toks2]==AP&&hd[toks2]==I&&tl[toks2]==NIL)
- return(cons(NIL,NIL));
- return(cons(NIL,toks2)); /*no tokens examined, whole grammar is `error'*/
- /* fprintf(stderr,"\nimpossible event in g_residue\n"),
- exit(1); /* grammar fn must have examined >=1 tokens */ }
- while(tag[tl[toks2]]==CONS)toks1=cons(hd[toks2],toks1),toks2=tl[toks2];
- if(tl[toks2]==NIL||tag[tl[toks2]]==AP&&hd[tl[toks2]]==I&&tl[tl[toks2]]==NIL)
- { toks1=cons(hd[toks2],toks1);
- return(cons(ap(DESTREV,toks1),NIL)); }
- return(cons(ap(DESTREV,toks1),toks2));
-}
-
-numplus(x,y)
-word x,y;
-{ if(tag[x]==DOUBLE)
- return(sto_dbl(get_dbl(x)+force_dbl(y)));
- if(tag[y]==DOUBLE)
- return(sto_dbl(bigtodbl(x)+get_dbl(y)));
- return(bigplus(x,y));
-}
-
-fn_error(s)
-char *s;
-{ fprintf(stderr,"\nprogram error: %s\n",s);
- outstats();
- exit(1); }
-
-getenv_error(char *a)
-{ fprintf(stderr,
- "program error: getenv(%s): illegal characters in result string\n",a);
- outstats();
- exit(1); }
-
-subs_error()
-{ fn_error("subscript out of range");
-}
-
-div_error()
-{ fn_error("attempt to divide by zero");
-}
-/* other arithmetic exceptions signal-trapped by fpe_error - see STEER */
-
-math_error(s)
-char *s;
-{ fprintf(stderr,"\nmath function %serror (%s)\n",
- errno==EDOM?"domain ":errno==ERANGE?"range ":"",s);
- outstats();
- exit(1);
-}
-
-word_error(s)
-char *s;
-{ fprintf(stderr,
- "\nprogram error: fractional number where integer expected (%s)\n",s);
- outstats();
- exit(1);
-}
-
-char *stdname(c)
-word c;
-{ return c==':' ? "$:-" : c=='-' ? "$-" : "$+"; }
-
-stdin_error(c)
-word c;
-{ if(stdinuse==c)
- fprintf(stderr,"program error: duplicate use of %s\n",stdname(c));
- else fprintf(stderr,"program error: simultaneous use of %s and %s\n",
- stdname(c), stdname(stdinuse));
- outstats();
- exit(1);
-}
-
-#ifdef BSDCLOCK
-#include <sys/times.h>
-#include <unistd.h>
-#ifndef CLK_TCK
-#define CLK_TCK sysconf(_SC_CLK_TCK)
-#endif
-#else
-/* this is ANSII C, POSIX */
-#include <time.h>
-clock_t start, end;
-#endif
-
-initclock()
-{
-#ifndef BSDCLOCK
-start=clock();
-#endif
-}
-
-out_here(f,h,nl) /* h is fileinfo(scriptname,line_no) */
-FILE *f;
-word h,nl;
-{ extern word errs;
- if(tag[h]!=FILEINFO)
- { fprintf(stderr,"(impossible event in outhere)\n"); return; }
- fprintf(f,"(line %3d of \"%s\")",tl[h],(char *)hd[h]);
- if(nl)putc('\n',f); else putc(' ',f);
- if(compiling&&!errs)errs=h; /* relevant only when called from steer.c */
-} /* `soft' error, set errs rather than errline, so not saved in dump */
-
-outstats()
-{ extern long claims,nogcs;
- extern word atcount;
- extern long long cellcount;
-#ifdef BSDCLOCK
- struct tms buffer;
-#endif
-#ifdef HISTO
- if(sourcemc)printhisto();
-#endif
- if(!atcount)return;
-#ifdef BSDCLOCK
- times(&buffer);
-#else
- end=clock();
-#endif
- printf("||");
- printf("reductions = %lld, cells claimed = %lld, ",
- cycles,cellcount+claims);
- printf("no of gc's = %ld, cpu = %0.2f",nogcs,
-#ifdef BSDCLOCK
- buffer.tms_utime/(CLK_TCK*1.0));
-#else
- ((double) (end - start)) / CLOCKS_PER_SEC);
-#endif
- putchar('\n');
-#ifdef DEBUG
- printf("||maxr_depth=%d\n",maxrdepth);
-#endif
-}
-
-/* end of MIRANDA REDUCE */
-
diff --git a/new/rules.y b/new/rules.y
deleted file mode 100644
index e44698b..0000000
--- a/new/rules.y
+++ /dev/null
@@ -1,1686 +0,0 @@
-/* Miranda token declarations and syntax rules for "YACC" */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-/* miranda symbols */
-
-%token VALUE EVAL WHERE IF TO LEFTARROW COLONCOLON COLON2EQ
- TYPEVAR NAME CNAME CONST DOLLAR2 OFFSIDE ELSEQ
- ABSTYPE WITH DIAG EQEQ FREE INCLUDE EXPORT TYPE
- OTHERWISE SHOWSYM PATHNAME BNF LEX ENDIR ERRORSY ENDSY
- EMPTYSY READVALSY LEXDEF CHARCLASS ANTICHARCLASS LBEGIN
-
-%right ARROW
-%right PLUSPLUS ':' MINUSMINUS
-%nonassoc DOTDOT
-%right VEL
-%right '&'
-%nonassoc '>' GE '=' NE LE '<'
-%left '+' '-'
-%left '*' '/' REM DIV
-%right '^'
-%left '.' /* fiddle to make '#' behave */
-%left '!'
-%right INFIXNAME INFIXCNAME
-%token CMBASE /* placeholder to start combinator values - see combs.h */
-
-%{
-/* the following definition has to be kept in line with the token declarations
- above */
-char *yysterm[]= {
- 0,
- "VALUE",
- "EVAL",
- "where",
- "if",
- "&>",
- "<-",
- "::",
- "::=",
- "TYPEVAR",
- "NAME",
- "CONSTRUCTOR-NAME",
- "CONST",
- "$$",
- "OFFSIDE",
- "OFFSIDE =",
- "abstype",
- "with",
- "//",
- "==",
- "%free",
- "%include",
- "%export",
- "type",
- "otherwise",
- "show",
- "PATHNAME",
- "%bnf",
- "%lex",
- "%%",
- "error",
- "end",
- "empty",
- "readvals",
- "NAME",
- "`char-class`",
- "`char-class`",
- "%%begin",
- "->",
- "++",
- "--",
- "..",
- "\\/",
- ">=",
- "~=",
- "<=",
- "mod",
- "div",
- "$NAME",
- "$CONSTRUCTOR"};
-
-%}
-
-/* Miranda syntax rules */
-/* the associated semantic actions perform the compilation */
-
-%{
-#include "data.h"
-#include "lex.h"
-extern word nill,k_i,Void;
-extern word message,standardout;
-extern word big_one;
-#define isltmess_t(t) (islist_t(t)&&tl[t]==message)
-#define isstring_t(t) (islist_t(t)&&tl[t]==char_t)
-extern word SYNERR,errs,echoing,gvars;
-extern word listdiff_fn,indent_fn,outdent_fn;
-extern word polyshowerror;
-word lastname=0;
-word suppressids=NIL;
-word idsused=NIL;
-word tvarscope=0;
-word includees=NIL,embargoes=NIL,exportfiles=NIL,freeids=NIL,exports=NIL;
-word lexdefs=NIL,lexstates=NIL,inlex=0,inexplist=0;
-word inbnf=0,col_fn=0,fnts=NIL,eprodnts=NIL,nonterminals=NIL,sreds=0;
-word ihlist=0,ntspecmap=NIL,ntmap=NIL,lasth=0;
-word obrct=0;
-
-void evaluate(x)
-word x;
-{ extern word debug;
- word t;
- t=type_of(x);
- if(t==wrong_t)return;
- lastexp=x;
- x=codegen(x);
- if(polyshowerror)return;
- if(process())
- /* setup new process for each evaluation */
- { (void)signal(SIGINT,(sighandler)dieclean);
- /* if interrupted will flush output etc before going */
- compiling=0;
- resetgcstats();
- output(isltmess_t(t)?x:
- cons(ap(standardout,isstring_t(t)?x
- :ap(mkshow(0,0,t),x)),NIL));
- (void)signal(SIGINT,SIG_IGN);/* otherwise could do outstats() twice */
- putchar('\n');
- outstats();
- exit(0); }
-}
-
-void obey(x) /* like evaluate but no fork, no stats, no extra '\n' */
-word x;
-{ word t=type_of(x);
- x=codegen(x);
- if(polyshowerror)return;
- compiling=0;
- output(isltmess_t(t)?x:
- cons(ap(standardout,isstring_t(t)?x:ap(mkshow(0,0,t),x)),NIL));
-}
-
-int isstring(x)
-word x;
-{ return(x==NILS||tag[x]==CONS&&is_char(hd[x]));
-}
-
-word compose(x) /* used in compiling 'cases' */
-word x;
-{ word y=hd[x];
- if(hd[y]==OTHERWISE)y=tl[y]; /* OTHERWISE was just a marker - lose it */
- else y=tag[y]==LABEL?label(hd[y],ap(tl[y],FAIL)):
- ap(y,FAIL); /* if all guards false result is FAIL */
- x = tl[x];
- if(x!=NIL)
- { while(tl[x]!=NIL)y=label(hd[hd[x]],ap(tl[hd[x]],y)), x=tl[x];
- y=ap(hd[x],y);
- /* first alternative has no label - label of enclosing rhs applies */
- }
- return(y);
-}
-
-word starts(x) /* x is grammar rhs - returns list of nonterminals in start set */
-word x;
-{ L: switch(tag[x])
- { case ID: return(cons(x,NIL));
- case LABEL:
- case LET:
- case LETREC: x=tl[x]; goto L;
- case AP: switch(hd[x])
- { case G_SYMB:
- case G_SUCHTHAT:
- case G_RULE: return(NIL);
- case G_OPT:
- case G_FBSTAR:
- case G_STAR: x=tl[x]; goto L;
- default: if(hd[x]==outdent_fn)
- { x=tl[x]; goto L; }
- if(tag[hd[x]]==AP)
- if(hd[hd[x]]==G_ERROR)
- { x=tl[hd[x]]; goto L; }
- if(hd[hd[x]]==G_SEQ)
- { if(eprod(tl[hd[x]]))
- return(UNION(starts(tl[hd[x]]),starts(tl[x])));
- x=tl[hd[x]]; goto L; } else
- if(hd[hd[x]]==G_ALT)
- return(UNION(starts(tl[hd[x]]),starts(tl[x])));
- else
- if(hd[hd[x]]==indent_fn)
- { x=tl[x]; goto L; }
- }
- default: return(NIL);
- }
-}
-
-int eprod(x) /* x is grammar rhs - does x admit empty production? */
-word x;
-{ L: switch(tag[x])
- { case ID: return(member(eprodnts,x));
- case LABEL:
- case LET:
- case LETREC: x=tl[x]; goto L;
- case AP: switch(hd[x])
- { case G_SUCHTHAT:
- case G_ANY:
- case G_SYMB: return(0);
- case G_RULE: return(1);
- case G_OPT:
- case G_FBSTAR:
- case G_STAR: return(1);
- default: if(hd[x]==outdent_fn)
- { x=tl[x]; goto L; }
- if(tag[hd[x]]==AP)
- if(hd[hd[x]]==G_ERROR)
- { x=tl[hd[x]]; goto L; }
- if(hd[hd[x]]==G_SEQ)
- return(eprod(tl[hd[x]])&&eprod(tl[x])); else
- if(hd[hd[x]]==G_ALT)
- return(eprod(tl[hd[x]])||eprod(tl[x]));
- else
- if(hd[hd[x]]==indent_fn)
- { x=tl[x]; goto L; }
- }
- default: return(x==G_STATE||x==G_UNIT);
- /* G_END is special case, unclear whether it counts as an e-prodn.
- decide no for now, sort this out later */
- }
-}
-
-word add_prod(d,ps,hr)
-word d,ps,hr;
-{ word p,n=dlhs(d);
- for(p=ps;p!=NIL;p=tl[p])
- if(dlhs(hd[p])==n)
- if(dtyp(d)==undef_t&&dval(hd[p])==UNDEF)
- { dval(hd[p])=dval(d); return(ps); } else
- if(dtyp(d)!=undef_t&&dtyp(hd[p])==undef_t)
- { dtyp(hd[p])=dtyp(d); return(ps); }
- else
- errs=hr,
- printf(
- "%ssyntax error: conflicting %s of nonterminal \"%s\"\n",
- echoing?"\n":"",
- dtyp(d)==undef_t?"definitions":"specifications",
- get_id(n)),
- acterror();
- return(cons(d,ps));
-}
-/* clumsy - this algorithm is quadratic in number of prodns - fix later */
-
-word getloc(nt,prods) /* get here info for nonterminal */
-word nt,prods;
-{ while(prods!=NIL&&dlhs(hd[prods])!=nt)prods=tl[prods];
- if(prods!=NIL)return(hd[dval(hd[prods])]);
- return(0); /* should not happen, but just in case */
-}
-
-void findnt(nt) /* set errs to here info of undefined nonterminal */
-word nt;
-{ word p=ntmap;
- while(p!=NIL&&hd[hd[p]]!=nt)p=tl[p];
- if(p!=NIL)
- { errs=tl[hd[p]]; return; }
- p=ntspecmap;
- while(p!=NIL&&hd[hd[p]]!=nt)p=tl[p];
- if(p!=NIL)errs=tl[hd[p]];
-}
-
-#define isap2(fn,x) (tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==(fn))
-#define firstsymb(term) tl[hd[term]]
-
-void binom(rhs,x)
-/* performs the binomial optimisation on rhs of nonterminal x
- x: x alpha1| ... | x alphaN | rest ||need not be in this order
- ==>
- x: rest (alpha1|...|alphaN)*
-*/
-word rhs,x;
-{ word *p= &tl[rhs]; /* rhs is of form label(hereinf, stuff) */
- word *lastp=0,*holdrhs,suffix,alpha=NIL;
- if(tag[*p]==LETREC)p = &tl[*p]; /* ignore trailing `where defs' */
- if(isap2(G_ERROR,*p))p = &tl[hd[*p]];
- holdrhs=p;
- while(isap2(G_ALT,*p))
- if(firstsymb(tl[hd[*p]])==x)
- alpha=cons(tl[tl[hd[*p]]],alpha),
- *p=tl[*p],p = &tl[*p];
- else lastp=p,p = &tl[tl[*p]];
- /* note each (G_ALT a b) except the outermost is labelled */
- if(lastp&&firstsymb(*p)==x)
- alpha=cons(tl[*p],alpha),
- *lastp=tl[hd[*lastp]];
- if(alpha==NIL)return;
- suffix=hd[alpha],alpha=tl[alpha];
- while(alpha!=NIL)
- suffix=ap2(G_ALT,hd[alpha],suffix),
- alpha=tl[alpha];
- *holdrhs=ap2(G_SEQ,*holdrhs,ap(G_FBSTAR,suffix));
-}
-/* should put some labels on the alpha's - fix later */
-
-word getcol_fn()
-{ extern char *dicp,*dicq;
- if(!col_fn)
- strcpy(dicp,"bnftokenindentation"),
- dicq=dicp+20,
- col_fn=name();
- return(col_fn);
-}
-
-void startbnf()
-{ ntspecmap=ntmap=nonterminals=NIL;
- if(fnts==0)col_fn=0; /* reinitialise, a precaution */
-}
-
-word ih_abstr(x) /* abstract inherited attributes from grammar rule */
-word x;
-{ word ih=ihlist;
- while(ih!=NIL) /* relies on fact that ihlist is reversed */
- x=lambda(hd[ih],x),ih=tl[ih];
- return(x);
-}
-
-int can_elide(x) /* is x of the form $1 applied to ih attributes in order? */
-word x;
-{ word ih;
- if(ihlist)
- for(ih=ihlist;ih!=NIL&&tag[x]==AP;ih=tl[ih],x=hd[x])
- if(hd[ih]!=tl[x])return(0);
- return(x==mkgvar(1));
-}
-
-int e_re(x) /* does regular expression x match empty string ? */
-{ L: if(tag[x]==AP)
- { if(hd[x]==LEX_STAR||hd[x]==LEX_OPT)return(1);
- if(hd[x]==LEX_STRING)return(tl[x]==NIL);
- if(tag[hd[x]]!=AP)return(0);
- if(hd[hd[x]]==LEX_OR)
- { if(e_re(tl[hd[x]]))return(1);
- x=tl[x]; goto L; } else
- if(hd[hd[x]]==LEX_SEQ)
- { if(!e_re(tl[hd[x]]))return(0);
- x=tl[x]; goto L; } else
- if(hd[hd[x]]==LEX_RCONTEXT)
- { x=tl[hd[x]]; goto L; }
- }
- return(0);
-}
-
-%}
-
-%%
-
-entity: /* the entity to be parsed is either a definition script or an
- expression (the latter appearing as a command line) */
-
- error|
-
- script
- = { lastname=0; /* outstats(); */ }|
- /* statistics not usually wanted after compilation */
-
-/* MAGIC exp '\n' script
- = { lastexp=$2; }| /* change to magic scripts 19.11.2013 */
-
- VALUE exp
- = { lastexp=$2; }| /* next line of `$+' */
-
- EVAL exp
- = { if(!SYNERR&&yychar==0)
- { evaluate($2); }
- }|
-
- EVAL exp COLONCOLON
- /* boring problem - how to make sure no junk chars follow here?
- likewise TO case -- trick used above doesn't work, yychar is
- here always -1 Why? Too fiddly to bother with just now */
- = { word t=type_of($2);
- if(t!=wrong_t)
- { lastexp=$2;
- if(tag[$2]==ID&&id_type($2)==wrong_t)t=wrong_t;
- out_type(t);
- putchar('\n'); }
- }|
-
- EVAL exp TO
- = { FILE *fil=NULL,*efil;
- word t=type_of($2);
- char *f=token(),*ef;
- if(f)keep(f); ef=token(); /* wasteful of dic space, FIX LATER */
- if(f){ fil= fopen(f,$3?"a":"w");
- if(fil==NULL)
- printf("cannot open \"%s\" for writing\n",f); }
- else printf("filename missing after \"&>\"\n");
- if(ef)
- { efil= fopen(ef,$3?"a":"w");
- if(efil==NULL)
- printf("cannot open \"%s\" for writing\n",ef); }
- if(t!=wrong_t)$2=codegen(lastexp=$2);
- if(polyshowerror)return;
- if(t!=wrong_t&&fil!=NULL&&(!ef||efil))
- { word pid;/* launch a concurrent process to perform task */
- sighandler oldsig;
- oldsig=signal(SIGINT,SIG_IGN); /* ignore interrupts */
- if(pid=fork())
- { /* "parent" */
- if(pid==-1)perror("cannot create process");
- else printf("process %d\n",pid);
- fclose(fil);
- if(ef)fclose(efil);
- (void)signal(SIGINT,oldsig); }else
- { /* "child" */
- (void)signal(SIGQUIT,SIG_IGN); /* and quits */
-#ifndef SYSTEM5
- (void)signal(SIGTSTP,SIG_IGN); /* and stops */
-#endif
- close(1); dup(fileno(fil)); /* subvert stdout */
- close(2); dup(fileno(ef?efil:fil)); /* subvert stderr */
- /* FUNNY BUG - if redirect stdout stderr to same file by two
- calls to freopen, their buffers get conflated - whence do
- by subverting underlying file descriptors, as above
- (fix due to Martin Guy) */
- /* formerly used dup2, but not present in system V */
- fclose(stdin);
- /* setbuf(stdout,NIL);
- /* not safe to change buffering of stream already in use */
- /* freopen would have reset the buffering automatically */
- lastexp = NIL; /* what else should we set to NIL? */
- /*atcount= 1; */
- compiling= 0;
- resetgcstats();
- output(isltmess_t(t)?$2:
- cons(ap(standardout,isstring_t(t)?$2:
- ap(mkshow(0,0,t),$2)),NIL));
- putchar('\n');
- outstats();
- exit(0); } } };
-
-script:
- /* empty */|
- defs;
-
-exp:
- op | /* will later suppress in favour of (op) in arg */
- e1;
-
-op:
- '~'
- = { $$ = NOT; }|
- '#'
- = { $$ = LENGTH; }|
- diop;
-
-diop:
- '-'
- = { $$ = MINUS; }|
- diop1;
-
-diop1:
- '+'
- = { $$ = PLUS; }|
- PLUSPLUS
- = { $$ = APPEND; }|
- ':'
- = { $$ = P; }|
- MINUSMINUS
- = { $$ = listdiff_fn; }|
- VEL
- = { $$ = OR; }|
- '&'
- = { $$ = AND; }|
- relop |
- '*'
- = { $$ = TIMES; }|
- '/'
- = { $$ = FDIV; }|
- DIV
- = { $$ = INTDIV; }|
- REM
- = { $$ = MOD; }|
- '^'
- = { $$ = POWER; }|
- '.'
- = { $$ = B; }|
- '!'
- = { $$ = ap(C,SUBSCRIPT); }|
- INFIXNAME|
- INFIXCNAME;
-
-relop:
- '>'
- = { $$ = GR; }|
- GE
- = { $$ = GRE; }|
- eqop
- = { $$ = EQ; }|
- NE
- = { $$ = NEQ; }|
- LE
- = { $$ = ap(C,GRE); }|
- '<'
- = { $$ = ap(C,GR); };
-
-eqop:
- EQEQ| /* silently accept for benefit of Haskell users */
- '=';
-
-rhs:
- cases WHERE ldefs
- = { $$ = block($3,compose($1),0); }|
- exp WHERE ldefs
- = { $$ = block($3,$1,0); }|
- exp|
- cases
- = { $$ = compose($1); };
-
-cases:
- exp ',' if exp
- = { $$ = cons(ap2(COND,$4,$1),NIL); }|
- exp ',' OTHERWISE
- = { $$ = cons(ap(OTHERWISE,$1),NIL); }|
- cases reindent ELSEQ alt
- = { $$ = cons($4,$1);
- if(hd[hd[$1]]==OTHERWISE)
- syntax("\"otherwise\" must be last case\n"); };
-
-alt:
- here exp
- = { errs=$1,
- syntax("obsolete syntax, \", otherwise\" missing\n");
- $$ = ap(OTHERWISE,label($1,$2)); }|
- here exp ',' if exp
- = { $$ = label($1,ap2(COND,$5,$2)); }|
- here exp ',' OTHERWISE
- = { $$ = ap(OTHERWISE,label($1,$2)); };
-
-if:
- /* empty */
- = { extern word strictif;
- if(strictif)syntax("\"if\" missing\n"); }|
- IF;
-
-indent:
- /* empty */
- = { if(!SYNERR){layout(); setlmargin();}
- };
-/* note that because of yacc's one symbol look ahead, indent must usually be
- invoked one symbol earlier than the non-terminal to which it applies
- - see `production:' for an exception */
-
-outdent:
- separator
- = { unsetlmargin(); };
-
-separator:
- OFFSIDE | ';' ;
-
-reindent:
- /* empty */
- = { if(!SYNERR)
- { unsetlmargin(); layout(); setlmargin(); }
- };
-
-liste: /* NB - returns list in reverse order */
- exp
- = { $$ = cons($1,NIL); }|
- liste ',' exp /* left recursive so as not to eat YACC stack */
- = { $$ = cons($3,$1); };
-
-e1:
- '~' e1 %prec '='
- = { $$ = ap(NOT,$2); }|
- e1 PLUSPLUS e1
- = { $$ = ap2(APPEND,$1,$3); }|
- e1 ':' e1
- = { $$ = cons($1,$3); }|
- e1 MINUSMINUS e1
- = { $$ = ap2(listdiff_fn,$1,$3); }|
- e1 VEL e1
- = { $$ = ap2(OR,$1,$3); }|
- e1 '&' e1
- = { $$ = ap2(AND,$1,$3); }|
- reln |
- e2;
-
-es1: /* e1 or presection */
- '~' e1 %prec '='
- = { $$ = ap(NOT,$2); }|
- e1 PLUSPLUS e1
- = { $$ = ap2(APPEND,$1,$3); }|
- e1 PLUSPLUS
- = { $$ = ap(APPEND,$1); }|
- e1 ':' e1
- = { $$ = cons($1,$3); }|
- e1 ':'
- = { $$ = ap(P,$1); }|
- e1 MINUSMINUS e1
- = { $$ = ap2(listdiff_fn,$1,$3); }|
- e1 MINUSMINUS
- = { $$ = ap(listdiff_fn,$1); }|
- e1 VEL e1
- = { $$ = ap2(OR,$1,$3); }|
- e1 VEL
- = { $$ = ap(OR,$1); }|
- e1 '&' e1
- = { $$ = ap2(AND,$1,$3); }|
- e1 '&'
- = { $$ = ap(AND,$1); }|
- relsn |
- es2;
-
-e2:
- '-' e2 %prec '-'
- = { $$ = ap(NEG,$2); }|
- '#' e2 %prec '.'
- = { $$ = ap(LENGTH,$2); }|
- e2 '+' e2
- = { $$ = ap2(PLUS,$1,$3); }|
- e2 '-' e2
- = { $$ = ap2(MINUS,$1,$3); }|
- e2 '*' e2
- = { $$ = ap2(TIMES,$1,$3); }|
- e2 '/' e2
- = { $$ = ap2(FDIV,$1,$3); }|
- e2 DIV e2
- = { $$ = ap2(INTDIV,$1,$3); } |
- e2 REM e2
- = { $$ = ap2(MOD,$1,$3); }|
- e2 '^' e2
- = { $$ = ap2(POWER,$1,$3); } |
- e2 '.' e2
- = { $$ = ap2(B,$1,$3); }|
- e2 '!' e2
- = { $$ = ap2(SUBSCRIPT,$3,$1); }|
- e3;
-
-es2: /* e2 or presection */
- '-' e2 %prec '-'
- = { $$ = ap(NEG,$2); }|
- '#' e2 %prec '.'
- = { $$ = ap(LENGTH,$2); }|
- e2 '+' e2
- = { $$ = ap2(PLUS,$1,$3); }|
- e2 '+'
- = { $$ = ap(PLUS,$1); }|
- e2 '-' e2
- = { $$ = ap2(MINUS,$1,$3); }|
- e2 '-'
- = { $$ = ap(MINUS,$1); }|
- e2 '*' e2
- = { $$ = ap2(TIMES,$1,$3); }|
- e2 '*'
- = { $$ = ap(TIMES,$1); }|
- e2 '/' e2
- = { $$ = ap2(FDIV,$1,$3); }|
- e2 '/'
- = { $$ = ap(FDIV,$1); }|
- e2 DIV e2
- = { $$ = ap2(INTDIV,$1,$3); } |
- e2 DIV
- = { $$ = ap(INTDIV,$1); } |
- e2 REM e2
- = { $$ = ap2(MOD,$1,$3); }|
- e2 REM
- = { $$ = ap(MOD,$1); }|
- e2 '^' e2
- = { $$ = ap2(POWER,$1,$3); } |
- e2 '^'
- = { $$ = ap(POWER,$1); } |
- e2 '.' e2
- = { $$ = ap2(B,$1,$3); }|
- e2 '.'
- = { $$ = ap(B,$1); }|
- e2 '!' e2
- = { $$ = ap2(SUBSCRIPT,$3,$1); }|
- e2 '!'
- = { $$ = ap2(C,SUBSCRIPT,$1); }|
- es3;
-
-e3:
- comb INFIXNAME e3
- = { $$ = ap2($2,$1,$3); }|
- comb INFIXCNAME e3
- = { $$ = ap2($2,$1,$3); }|
- comb;
-
-es3: /* e3 or presection */
- comb INFIXNAME e3
- = { $$ = ap2($2,$1,$3); }|
- comb INFIXNAME
- = { $$ = ap($2,$1); }|
- comb INFIXCNAME e3
- = { $$ = ap2($2,$1,$3); }|
- comb INFIXCNAME
- = { $$ = ap($2,$1); }|
- comb;
-
-comb:
- comb arg
- = { $$ = ap($1,$2); }|
- arg;
-
-reln:
- e2 relop e2
- = { $$ = ap2($2,$1,$3); }|
- reln relop e2
- = { word subject;
- subject = hd[hd[$1]]==AND?tl[tl[$1]]:tl[$1];
- $$ = ap2(AND,$1,ap2($2,subject,$3));
- }; /* EFFICIENCY PROBLEM - subject gets re-evaluated (and
- retypechecked) - fix later */
-
-relsn: /* reln or presection */
- e2 relop e2
- = { $$ = ap2($2,$1,$3); }|
- e2 relop
- = { $$ = ap($2,$1); }|
- reln relop e2
- = { word subject;
- subject = hd[hd[$1]]==AND?tl[tl[$1]]:tl[$1];
- $$ = ap2(AND,$1,ap2($2,subject,$3));
- }; /* EFFICIENCY PROBLEM - subject gets re-evaluated (and
- retypechecked) - fix later */
-
-arg:
- { if(!SYNERR)lexstates=NIL,inlex=1; }
- LEX lexrules ENDIR
- = { inlex=0; lexdefs=NIL;
- if(lexstates!=NIL)
- { word echoed=0;
- for(;lexstates!=NIL;lexstates=tl[lexstates])
- { if(!echoed)printf(echoing?"\n":""),echoed=1;
- if(!(tl[hd[lexstates]]&1))
- printf("warning: lex state %s is never entered\n",
- get_id(hd[hd[lexstates]])); else
- if(!(tl[hd[lexstates]]&2))
- printf("warning: lex state %s has no associated rules\n",
- get_id(hd[hd[lexstates]])); }
- }
- if($3==NIL)syntax("%lex with no rules\n");
- else tag[$3]=LEXER;
- /* result is lex-list, in reverse order, of items of the form
- cons(scstuff,cons(matcher,rhs))
- where scstuff is of the form
- cons(0-or-list-of-startconditions,1+newstartcondition)
- */
- $$ = $3; }|
- NAME |
- CNAME |
- CONST |
- READVALSY
- = { $$ = readvals(0,0); }|
- SHOWSYM
- = { $$ = show(0,0); }|
- DOLLAR2
- = { $$ = lastexp;
- if(lastexp==UNDEF)
- syntax("no previous expression to substitute for $$\n"); }|
- '[' ']'
- = { $$ = NIL; }|
- '[' exp ']'
- = { $$ = cons($2,NIL); }|
- '[' exp ',' exp ']'
- = { $$ = cons($2,cons($4,NIL)); }|
- '[' exp ',' exp ',' liste ']'
- = { $$ = cons($2,cons($4,reverse($6))); }|
- '[' exp DOTDOT exp ']'
- = { $$ = ap3(STEPUNTIL,big_one,$4,$2); }|
- '[' exp DOTDOT ']'
- = { $$ = ap2(STEP,big_one,$2); }|
- '[' exp ',' exp DOTDOT exp ']'
- = { $$ = ap3(STEPUNTIL,ap2(MINUS,$4,$2),$6,$2); }|
- '[' exp ',' exp DOTDOT ']'
- = { $$ = ap2(STEP,ap2(MINUS,$4,$2),$2); }|
- '[' exp '|' qualifiers ']'
- = { $$ = SYNERR?NIL:compzf($2,$4,0); }|
- '[' exp DIAG qualifiers ']'
- = { $$ = SYNERR?NIL:compzf($2,$4,1); }|
- '(' op ')' /* RSB */
- = { $$ = $2; }|
- '(' es1 ')' /* presection or parenthesised e1 */
- = { $$ = $2; }|
- '(' diop1 e1 ')' /* postsection */
- = { $$ = (tag[$2]==AP&&hd[$2]==C)?ap(tl[$2],$3): /* optimisation */
- ap2(C,$2,$3); }|
- '(' ')'
- = { $$ = Void; }| /* the void tuple */
- '(' exp ',' liste ')'
- = { if(tl[$4]==NIL)$$=pair($2,hd[$4]);
- else { $$=pair(hd[tl[$4]],hd[$4]);
- $4=tl[tl[$4]];
- while($4!=NIL)$$=tcons(hd[$4],$$),$4=tl[$4];
- $$ = tcons($2,$$); }
- /* representation of the tuple (a1,...,an) is
- tcons(a1,tcons(a2,...pair(a(n-1),an))) */
- };
-
-lexrules:
- lexrules lstart here re indent { if(!SYNERR)inlex=2; }
- ARROW exp lpostfix { if(!SYNERR)inlex=1; } outdent
- = { if($9<0 && e_re($4))
- errs=$3,
- syntax("illegal lex rule - lhs matches empty\n");
- $$ = cons(cons(cons($2,1+$9),cons($4,label($3,$8))),$1); }|
- lexdefs
- = { $$ = NIL; };
-
-lstart:
- /* empty */
- = { $$ = 0; }|
- '<' cnames '>'
- = { word ns=NIL;
- for(;$2!=NIL;$2=tl[$2])
- { word *x = &lexstates,i=1;
- while(*x!=NIL&&hd[hd[*x]]!=hd[$2])i++,x = &tl[*x];
- if(*x == NIL)*x = cons(cons(hd[$2],2),NIL);
- else tl[hd[*x]] |= 2;
- ns = add1(i,ns); }
- $$ = ns; };
-
-cnames:
- CNAME
- = { $$=cons($1,NIL); }|
- cnames CNAME
- = { if(member($1,$2))
- printf("%ssyntax error: repeated name \"%s\" in start conditions\n",
- echoing?"\n":"",get_id($2)),
- acterror();
- $$ = cons($2,$1); };
-
-lpostfix:
- /* empty */
- = { $$ = -1; }|
- LBEGIN CNAME
- = { word *x = &lexstates,i=1;
- while(*x!=NIL&&hd[hd[*x]]!=$2)i++,x = &tl[*x];
- if(*x == NIL)*x = cons(cons($2,1),NIL);
- else tl[hd[*x]] |= 1;
- $$ = i;
- }|
- LBEGIN CONST
- = { if(!isnat($2)||get_word($2)!=0)
- syntax("%begin not followed by IDENTIFIER or 0\n");
- $$ = 0; };
-
-lexdefs:
- lexdefs LEXDEF indent '=' re outdent
- = { lexdefs = cons(cons($2,$5),lexdefs); }|
- /* empty */
- = { lexdefs = NIL; };
-
-re: /* regular expression */
- re1 '|' re
- { $$ = ap2(LEX_OR,$1,$3); }|
- re1;
-
-re1:
- lterm '/' lterm
- { $$ = ap2(LEX_RCONTEXT,$1,$3); }|
- lterm '/'
- { $$ = ap2(LEX_RCONTEXT,$1,0); }|
- lterm;
-
-lterm:
- lfac lterm
- { $$ = ap2(LEX_SEQ,$1,$2); }|
- lfac;
-
-lfac:
- lunit '*'
- { if(e_re($1))
- syntax("illegal regular expression - arg of * matches empty\n");
- $$ = ap(LEX_STAR,$1); }|
- lunit '+'
- { $$ = ap2(LEX_SEQ,$1,ap(LEX_STAR,$1)); }|
- lunit '?'
- { $$ = ap(LEX_OPT,$1); }|
- lunit;
-
-lunit:
- '(' re ')'
- = { $$ = $2; }|
- CONST
- = { if(!isstring($1))
- printf("%ssyntax error - unexpected token \"",
- echoing?"\n":""),
- out(stdout,$1),printf("\" in regular expression\n"),
- acterror();
- $$ = $1==NILS?ap(LEX_STRING,NIL):
- tl[$1]==NIL?ap(LEX_CHAR,hd[$1]):
- ap(LEX_STRING,$1);
- }|
- CHARCLASS
- = { if($1==NIL)
- syntax("empty character class `` cannot match\n");
- $$ = tl[$1]==NIL?ap(LEX_CHAR,hd[$1]):ap(LEX_CLASS,$1); }|
- ANTICHARCLASS
- = { $$ = ap(LEX_CLASS,cons(ANTICHARCLASS,$1)); }|
- '.'
- = { $$ = LEX_DOT; }|
- name
- = { word x=lexdefs;
- while(x!=NIL&&hd[hd[x]]!=$1)x=tl[x];
- if(x==NIL)
- printf(
- "%ssyntax error: undefined lexeme %s in regular expression\n",
- echoing?"\n":"",
- get_id($1)),
- acterror();
- else $$ = tl[hd[x]]; };
-
-name: NAME|CNAME;
-
-qualifiers:
- exp
- = { $$ = cons(cons(GUARD,$1),NIL); }|
- generator
- = { $$ = cons($1,NIL); }|
- qualifiers ';' generator
- = { $$ = cons($3,$1); }|
- qualifiers ';' exp
- = { $$ = cons(cons(GUARD,$3),$1); };
-
-generator:
- e1 ',' generator
- = { /* fix syntax to disallow patlist on lhs of iterate generator */
- if(hd[$3]==GENERATOR)
- { word e=tl[tl[$3]];
- if(tag[e]==AP&&tag[hd[e]]==AP&&
- (hd[hd[e]]==ITERATE||hd[hd[e]]==ITERATE1))
- syntax("ill-formed generator\n"); }
- $$ = cons(REPEAT,cons(genlhs($1),$3)); idsused=NIL; }|
- generator1;
-
-generator1:
- e1 LEFTARROW exp
- = { $$ = cons(GENERATOR,cons(genlhs($1),$3)); idsused=NIL; }|
- e1 LEFTARROW exp ',' exp DOTDOT
- = { word p = genlhs($1); idsused=NIL;
- $$ = cons(GENERATOR,
- cons(p,ap2(irrefutable(p)?ITERATE:ITERATE1,
- lambda(p,$5),$3)));
- };
-
-defs:
- def|
- defs def;
-
-def:
- v act2 indent '=' here rhs outdent
- = { word l = $1, r = $6;
- word f = head(l);
- if(tag[f]==ID&&!isconstructor(f)) /* fnform defn */
- while(tag[l]==AP)r=lambda(tl[l],r),l=hd[l];
- r = label($5,r); /* to help locate type errors */
- declare(l,r),lastname=l; }|
-
- spec
- = { word h=reverse(hd[$1]),hr=hd[tl[$1]],t=tl[tl[$1]];
- while(h!=NIL&&!SYNERR)specify(hd[h],t,hr),h=tl[h];
- $$ = cons(nill,NIL); }|
-
- ABSTYPE here typeforms indent WITH lspecs outdent
- = { extern word TABSTRS;
- extern char *dicp,*dicq;
- word x=reverse($6),ids=NIL,tids=NIL;
- while(x!=NIL&&!SYNERR)
- specify(hd[hd[x]],cons(tl[tl[hd[x]]],NIL),hd[tl[hd[x]]]),
- ids=cons(hd[hd[x]],ids),x=tl[x];
- /* each id in specs has its id_type set to const(t,NIL) as a way
- of flagging that t is an abstract type */
- x=reverse($3);
- while(x!=NIL&&!SYNERR)
- { word shfn;
- decltype(hd[x],abstract_t,undef_t,$2);
- tids=cons(head(hd[x]),tids);
- /* check for presence of showfunction */
- (void)strcpy(dicp,"show");
- (void)strcat(dicp,get_id(hd[tids]));
- dicq = dicp+strlen(dicp)+1;
- shfn=name();
- if(member(ids,shfn))
- t_showfn(hd[tids])=shfn;
- x=tl[x]; }
- TABSTRS = cons(cons(tids,ids),TABSTRS);
- $$ = cons(nill,NIL); }|
-
- typeform indent act1 here EQEQ type act2 outdent
- = { word x=redtvars(ap($1,$6));
- decltype(hd[x],synonym_t,tl[x],$4);
- $$ = cons(nill,NIL); }|
-
- typeform indent act1 here COLON2EQ construction act2 outdent
- = { word rhs = $6, r_ids = $6, n=0;
- while(r_ids!=NIL)r_ids=tl[r_ids],n++;
- while(rhs!=NIL&&!SYNERR)
- { word h=hd[rhs],t=$1,stricts=NIL,i=0;
- while(tag[h]==AP)
- { if(tag[tl[h]]==AP&&hd[tl[h]]==strict_t)
- stricts=cons(i,stricts),tl[h]=tl[tl[h]];
- t=ap2(arrow_t,tl[h],t),h=hd[h],i++; }
- if(tag[h]==ID)
- declconstr(h,--n,t);
- /* warning - type not yet in reduced form */
- else { stricts=NIL;
- if(echoing)putchar('\n');
- printf("syntax error: illegal construct \"");
- out_type(hd[rhs]);
- printf("\" on right of ::=\n");
- acterror(); } /* can this still happen? check later */
- if(stricts!=NIL) /* ! operators were present */
- { word k = id_val(h);
- while(stricts!=NIL)
- k=ap2(MKSTRICT,i-hd[stricts],k),
- stricts=tl[stricts];
- id_val(h)=k; /* overwrite id_val of original constructor */
- }
- r_ids=cons(h,r_ids);
- rhs = tl[rhs]; }
- if(!SYNERR)decltype($1,algebraic_t,r_ids,$4);
- $$ = cons(nill,NIL); }|
-
- indent setexp EXPORT parts outdent
- = { inexplist=0;
- if(exports!=NIL)
- errs=$2,
- syntax("multiple %export statements are illegal\n");
- else { if($4==NIL&&exportfiles==NIL&&embargoes!=NIL)
- exportfiles=cons(PLUS,NIL);
- exports=cons($2,$4); } /* cons(hereinfo,identifiers) */
- $$ = cons(nill,NIL); }|
-
- FREE here '{' specs '}'
- = { if(freeids!=NIL)
- errs=$2,
- syntax("multiple %free statements are illegal\n"); else
- { word x=reverse($4);
- while(x!=NIL&&!SYNERR)
- { specify(hd[hd[x]],tl[tl[hd[x]]],hd[tl[hd[x]]]);
- freeids=cons(head(hd[hd[x]]),freeids);
- if(tl[tl[hd[x]]]==type_t)
- t_class(hd[freeids])=free_t;
- else id_val(hd[freeids])=FREE; /* conventional value */
- x=tl[x]; }
- fil_share(hd[files])=0; /* parameterised scripts unshareable */
- freeids=alfasort(freeids);
- for(x=freeids;x!=NIL;x=tl[x])
- hd[x]=cons(hd[x],cons(datapair(get_id(hd[x]),0),
- id_type(hd[x])));
- /* each element of freeids is of the form
- cons(id,cons(original_name,type)) */
- }
- $$ = cons(nill,NIL); }|
-
- INCLUDE bindings modifiers outdent
- /* fiddle - 'indent' done by yylex() on reading fileid */
- = { extern char *dicp;
- extern word CLASHES,BAD_DUMP;
- includees=cons(cons($1,cons($3,$2)),includees);
- /* $1 contains file+hereinfo */
- $$ = cons(nill,NIL); }|
-
- here BNF { startbnf(); inbnf=1;} names outdent productions ENDIR
- /* fiddle - `indent' done by yylex() while processing directive */
- = { word lhs=NIL,p=$6,subjects,body,startswith=NIL,leftrecs=NIL;
- ihlist=inbnf=0;
- nonterminals=UNION(nonterminals,$4);
- for(;p!=NIL;p=tl[p])
- if(dval(hd[p])==UNDEF)nonterminals=add1(dlhs(hd[p]),nonterminals);
- else lhs=add1(dlhs(hd[p]),lhs);
- nonterminals=setdiff(nonterminals,lhs);
- if(nonterminals!=NIL)
- errs=$1,
- member($4,hd[nonterminals])||findnt(hd[nonterminals]),
- printf("%sfatal error in grammar, ",echoing?"\n":""),
- printf("undefined nonterminal%s: ",
- tl[nonterminals]==NIL?"":"s"),
- printlist("",nonterminals),
- acterror(); else
- { /* compute list of nonterminals admitting empty prodn */
- eprodnts=NIL;
- L:for(p=$6;p!=NIL;p=tl[p])
- if(!member(eprodnts,dlhs(hd[p]))&&eprod(dval(hd[p])))
- { eprodnts=cons(dlhs(hd[p]),eprodnts); goto L; }
- /* now compute startswith reln between nonterminals
- (performing binomial transformation en route)
- and use to detect unremoved left recursion */
- for(p=$6;p!=NIL;p=tl[p])
- if(member(lhs=starts(dval(hd[p])),dlhs(hd[p])))
- binom(dval(hd[p]),dlhs(hd[p])),
- startswith=cons(cons(dlhs(hd[p]),starts(dval(hd[p]))),
- startswith);
- else startswith=cons(cons(dlhs(hd[p]),lhs),startswith);
- startswith=tclos(sortrel(startswith));
- for(;startswith!=NIL;startswith=tl[startswith])
- if(member(tl[hd[startswith]],hd[hd[startswith]]))
- leftrecs=add1(hd[hd[startswith]],leftrecs);
- if(leftrecs!=NIL)
- errs=getloc(hd[leftrecs],$6),
- printf("%sfatal error in grammar, ",echoing?"\n":""),
- printlist("irremovable left recursion: ",leftrecs),
- acterror();
- if($4==NIL) /* implied start symbol */
- $4=cons(dlhs(hd[lastlink($6)]),NIL);
- fnts=1; /* fnts is flag indicating %bnf in use */
- if(tl[$4]==NIL) /* only one start symbol */
- subjects=getfname(hd[$4]),
- body=ap2(G_CLOSE,str_conv(get_id(hd[$4])),hd[$4]);
- else
- { body=subjects=Void;
- while($4!=NIL)
- subjects=pair(getfname(hd[$4]),subjects),
- body=pair(
- ap2(G_CLOSE,str_conv(get_id(hd[$4])),hd[$4]),
- body),
- $4=tl[$4];
- }
- declare(subjects,label($1,block($6,body, 0)));
- }};
-
-setexp:
- here
- = { $$=$1;
- inexplist=1; }; /* hack to fix lex analyser */
-
-bindings:
- /* empty */
- = { $$ = NIL; }|
- '{' bindingseq '}'
- = { $$ = $2; };
-
-bindingseq:
- bindingseq binding
- = { $$ = cons($2,$1); }|
- binding
- = { $$ = cons($1,NIL); };
-
-binding:
- NAME indent '=' exp outdent
- = { $$ = cons($1,$4); }|
- typeform indent act1 EQEQ type act2 outdent
- = { word x=redtvars(ap($1,$5));
- word arity=0,h=hd[x];
- while(tag[h]==AP)arity++,h=hd[h];
- $$ = ap(h,make_typ(arity,0,synonym_t,tl[x]));
- };
-
-modifiers:
- /* empty */
- = { $$ = NIL; }|
- negmods
- = { word a,b,c=0;
- for(a=$1;a!=NIL;a=tl[a])
- for(b=tl[a];b!=NIL;b=tl[b])
- { if(hd[hd[a]]==hd[hd[b]])c=hd[hd[a]];
- if(tl[hd[a]]==tl[hd[b]])c=tl[hd[a]];
- if(c)break; }
- if(c)printf(
- "%ssyntax error: conflicting aliases (\"%s\")\n",
- echoing?"\n":"",
- get_id(c)),
- acterror();
- };
-
-negmods:
- negmods negmod
- = { $$ = cons($2,$1); }|
- negmod
- = { $$ = cons($1,NIL); };
-
-negmod:
- NAME '/' NAME
- = { $$ = cons($1,$3); }|
- CNAME '/' CNAME
- = { $$ = cons($1,$3); }|
- '-' NAME
- = { $$ = cons(make_pn(UNDEF),$2); }/*|
- '-' CNAME */; /* no - cannot suppress constructors selectively */
-
-here:
- /* empty */
- = { extern word line_no;
- lasth = $$ = fileinfo(get_fil(current_file),line_no);
- /* (script,line_no) for diagnostics */
- };
-
-act1:
- /* empty */
- = { tvarscope=1; };
-
-act2:
- /* empty */
- = { tvarscope=0; idsused= NIL; };
-
-ldefs:
- ldef
- = { $$ = cons($1,NIL);
- dval($1) = tries(dlhs($1),cons(dval($1),NIL));
- if(!SYNERR&&get_ids(dlhs($1))==NIL)
- errs=hd[hd[tl[dval($1)]]],
- syntax("illegal lhs for local definition\n");
- }|
- ldefs ldef
- = { if(dlhs($2)==dlhs(hd[$1]) /*&&dval(hd[$1])!=UNDEF*/)
- { $$ = $1;
- if(!fallible(hd[tl[dval(hd[$1])]]))
- errs=hd[dval($2)],
- printf("%ssyntax error: \
-unreachable case in defn of \"%s\"\n",echoing?"\n":"",get_id(dlhs($2))),
- acterror();
- tl[dval(hd[$1])]=cons(dval($2),tl[dval(hd[$1])]); }
- else if(!SYNERR)
- { word ns=get_ids(dlhs($2)),hr=hd[dval($2)];
- if(ns==NIL)
- errs=hr,
- syntax("illegal lhs for local definition\n");
- $$ = cons($2,$1);
- dval($2)=tries(dlhs($2),cons(dval($2),NIL));
- while(ns!=NIL&&!SYNERR) /* local nameclash check */
- { nclashcheck(hd[ns],$1,hr);
- ns=tl[ns]; }
- /* potentially quadratic - fix later */
- }
- };
-
-ldef:
- spec
- = { errs=hd[tl[$1]];
- syntax("`::' encountered in local defs\n");
- $$ = cons(nill,NIL); }|
- typeform here EQEQ
- = { errs=$2;
- syntax("`==' encountered in local defs\n");
- $$ = cons(nill,NIL); }|
- typeform here COLON2EQ
- = { errs=$2;
- syntax("`::=' encountered in local defs\n");
- $$ = cons(nill,NIL); }|
- v act2 indent '=' here rhs outdent
- = { word l = $1, r = $6;
- word f = head(l);
- if(tag[f]==ID&&!isconstructor(f)) /* fnform defn */
- while(tag[l]==AP)r=lambda(tl[l],r),l=hd[l];
- r = label($5,r); /* to help locate type errors */
- $$ = defn(l,undef_t,r); };
-
-vlist:
- v
- = { $$ = cons($1,NIL); }|
- vlist ',' v /* left recursive so as not to eat YACC stack */
- = { $$ = cons($3,$1); }; /* reverse order, NB */
-
-v:
- v1 |
- v1 ':' v
- = { $$ = cons($1,$3); };
-
-v1:
- v1 '+' CONST /* n+k pattern */
- = { if(!isnat($3))
- syntax("inappropriate use of \"+\" in pattern\n");
- $$ = ap2(PLUS,$3,$1); }|
- '-' CONST
- = { /* if(tag[$2]==DOUBLE)
- $$ = cons(CONST,sto_dbl(-get_dbl($2))); else */
- if(tag[$2]==INT)
- $$ = cons(CONST,bignegate($2)); else
- syntax("inappropriate use of \"-\" in pattern\n"); }|
- v2 INFIXNAME v1
- = { $$ = ap2($2,$1,$3); }|
- v2 INFIXCNAME v1
- = { $$ = ap2($2,$1,$3); }|
- v2;
-
-v2:
- v3 |
- v2 v3
- = { $$ = ap(hd[$1]==CONST&&tag[tl[$1]]==ID?tl[$1]:$1,$2); };
- /* repeated name apparatus may have wrapped CONST around leading id
- - not wanted */
-
-v3:
- NAME
- = { if(sreds&&member(gvars,$1))syntax("illegal use of $num symbol\n");
- /* cannot use grammar variable in a binding position */
- if(memb(idsused,$1))$$ = cons(CONST,$1);
- /* picks up repeated names in a template */
- else idsused= cons($1,idsused); } |
- CNAME |
- CONST
- = { if(tag[$1]==DOUBLE)
- syntax("use of floating point literal in pattern\n");
- $$ = cons(CONST,$1); }|
- '[' ']'
- = { $$ = nill; }|
- '[' vlist ']'
- = { word x=$2,y=nill;
- while(x!=NIL)y = cons(hd[x],y), x = tl[x];
- $$ = y; }|
- '(' ')'
- = { $$ = Void; }|
- '(' v ')'
- = { $$ = $2; }|
- '(' v ',' vlist ')'
- = { if(tl[$4]==NIL)$$=pair($2,hd[$4]);
- else { $$=pair(hd[tl[$4]],hd[$4]);
- $4=tl[tl[$4]];
- while($4!=NIL)$$=tcons(hd[$4],$$),$4=tl[$4];
- $$ = tcons($2,$$); }
- /* representation of the tuple (a1,...,an) is
- tcons(a1,tcons(a2,...pair(a(n-1),an))) */
- };
-
-type:
- type1 |
- type ARROW type
- = { $$ = ap2(arrow_t,$1,$3); };
-
-type1:
- type2 INFIXNAME type1
- = { $$ = ap2($2,$1,$3); }|
- type2;
-
-type2:
- /* type2 argtype /* too permissive - fix later */
- /* = { $$ = ap($1,$2); }| */
- tap|
- argtype;
-
-tap:
- NAME argtype
- = { $$ = ap($1,$2); }|
- tap argtype
- = { $$ = ap($1,$2); };
-
-argtype:
- NAME
- = { $$ = transtypeid($1); }|
- /* necessary while prelude not meta_tchecked (for prelude)*/
- typevar
- = { if(tvarscope&&!memb(idsused,$1))
- printf("%ssyntax error: unbound type variable ",echoing?"\n":""),
- out_type($1),putchar('\n'),acterror();
- $$ = $1; }|
- '(' typelist ')'
- = { $$ = $2; }|
- '[' type ']' /* at release one was `typelist' */
- = { $$ = ap(list_t,$2); }|
- '[' type ',' typel ']'
- = { syntax(
- "tuple-type with missing parentheses (obsolete syntax)\n"); };
-
-typelist:
- /* empty */
- = { $$ = void_t; }| /* voidtype */
- type |
- type ',' typel
- = { word x=$3,y=void_t;
- while(x!=NIL)y = ap2(comma_t,hd[x],y), x = tl[x];
- $$ = ap2(comma_t,$1,y); };
-
-typel:
- type
- = { $$ = cons($1,NIL); }|
- typel ',' type /* left recursive so as not to eat YACC stack */
- = { $$ = cons($3,$1); };
-
-parts: /* returned in reverse order */
- parts NAME
- = { $$ = add1($2,$1); }|
- parts '-' NAME
- = { $$ = $1; embargoes=add1($3,embargoes); }|
- parts PATHNAME
- = { $$ = $1; }| /*the pathnames are placed on exportfiles in yylex*/
- parts '+'
- = { $$ = $1;
- exportfiles=cons(PLUS,exportfiles); }|
- NAME
- = { $$ = add1($1,NIL); }|
- '-' NAME
- = { $$ = NIL; embargoes=add1($2,embargoes); }|
- PATHNAME
- = { $$ = NIL; }|
- '+'
- = { $$ = NIL;
- exportfiles=cons(PLUS,exportfiles); };
-
-specs: /* returns a list of cons(id,cons(here,type))
- in reverse order of appearance */
- specs spec
- = { word x=$1,h=hd[$2],t=tl[$2];
- while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
- $$ = x; }|
- spec
- = { word x=NIL,h=hd[$1],t=tl[$1];
- while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
- $$ = x; };
-
-spec:
- typeforms indent here COLONCOLON ttype outdent
- = { $$ = cons($1,cons($3,$5)); };
- /* hack: `typeforms' includes `namelist' */
-
-lspecs: /* returns a list of cons(id,cons(here,type))
- in reverse order of appearance */
- lspecs lspec
- = { word x=$1,h=hd[$2],t=tl[$2];
- while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
- $$ = x; }|
- lspec
- = { word x=NIL,h=hd[$1],t=tl[$1];
- while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
- $$ = x; };
-
-lspec:
- namelist indent here {inbnf=0;} COLONCOLON type outdent
- = { $$ = cons($1,cons($3,$6)); };
-
-namelist:
- NAME ',' namelist
- = { $$ = cons($1,$3); }|
- NAME
- = { $$ = cons($1,NIL); };
-
-typeforms:
- typeforms ',' typeform act2
- = { $$ = cons($3,$1); }|
- typeform act2
- = { $$ = cons($1,NIL); };
-
-typeform:
- CNAME typevars
- = { syntax("upper case identifier out of context\n"); }|
- NAME typevars /* warning if typevar is repeated */
- = { $$ = $1;
- idsused=$2;
- while($2!=NIL)
- $$ = ap($$,hd[$2]),$2 = tl[$2];
- }|
- typevar INFIXNAME typevar
- = { if(eqtvar($1,$3))
- syntax("repeated type variable in typeform\n");
- idsused=cons($1,cons($3,NIL));
- $$ = ap2($2,$1,$3); }|
- typevar INFIXCNAME typevar
- = { syntax("upper case identifier cannot be used as typename\n"); };
-
-ttype:
- type|
- TYPE
- = { $$ = type_t; };
-
-typevar:
- '*'
- = { $$ = mktvar(1); }|
- TYPEVAR;
-
-typevars:
- /* empty */
- = { $$ = NIL; }|
- typevar typevars
- = { if(memb($2,$1))
- syntax("repeated type variable on lhs of type def\n");
- $$ = cons($1,$2); };
-
-construction:
- constructs
- = { extern word SGC; /* keeps track of sui-generis constructors */
- if( tl[$1]==NIL && tag[hd[$1]]!=ID )
- /* 2nd conjunct excludes singularity types */
- SGC=cons(head(hd[$1]),SGC);
- };
-
-constructs:
- construct
- = { $$ = cons($1,NIL); }|
- constructs '|' construct
- = { $$ = cons($3,$1); };
-
-construct:
- field here INFIXCNAME field
- = { $$ = ap2($3,$1,$4);
- id_who($3)=$2; }|
- construct1;
-
-construct1:
- '(' construct ')'
- = { $$ = $2; }|
- construct1 field1
- = { $$ = ap($1,$2); }|
- here CNAME
- = { $$ = $2;
- id_who($2)=$1; };
-
-field:
- type|
- argtype '!'
- = { $$ = ap(strict_t,$1); };
-
-field1:
- argtype '!'
- = { $$ = ap(strict_t,$1); }|
- argtype;
-
-names: /* used twice - for bnf list, and for inherited attr list */
- /* empty */
- = { $$ = NIL; }|
- names NAME
- = { if(member($1,$2))
- printf("%ssyntax error: repeated identifier \"%s\" in %s list\n",
- echoing?"\n":"",get_id($2),inbnf?"bnf":"attribute"),
- acterror();
- $$ = inbnf?add1($2,$1):cons($2,$1);
- };
-
-productions:
- lspec
- = { word h=reverse(hd[$1]),hr=hd[tl[$1]],t=tl[tl[$1]];
- inbnf=1;
- $$=NIL;
- while(h!=NIL&&!SYNERR)
- ntspecmap=cons(cons(hd[h],hr),ntspecmap),
- $$=add_prod(defn(hd[h],t,UNDEF),$$,hr),
- h=tl[h];
- }|
- production
- = { $$ = cons($1,NIL); }|
- productions lspec
- = { word h=reverse(hd[$2]),hr=hd[tl[$2]],t=tl[tl[$2]];
- inbnf=1;
- $$=$1;
- while(h!=NIL&&!SYNERR)
- ntspecmap=cons(cons(hd[h],hr),ntspecmap),
- $$=add_prod(defn(hd[h],t,UNDEF),$$,hr),
- h=tl[h];
- }|
- productions production
- = { $$ = add_prod($2,$1,hd[dval($2)]); };
-
-production:
- NAME params ':' indent grhs outdent
- /* found by experiment that indent must follow ':' here */
- = { $$ = defn($1,undef_t,$5); };
-
-params: /* places inherited attributes, if any, on ihlist */
- /* empty */
- = { ihlist=0; }|
- { inbnf=0; } '(' names ')'
- = { inbnf=1;
- if($3==NIL)syntax("unexpected token ')'\n");
- ihlist=$3; }
-
-grhs:
- here phrase
- = { $$ = label($1,$2); };
-
-phrase:
- error_term
- = { $$ = ap2(G_ERROR,G_ZERO,$1); }|
- phrase1
- = { $$=hd[$1], $1=tl[$1];
- while($1!=NIL)
- $$=label(hd[$1],$$),$1=tl[$1],
- $$=ap2(G_ALT,hd[$1],$$),$1=tl[$1];
- }|
- phrase1 '|' error_term
- = { $$=hd[$1], $1=tl[$1];
- while($1!=NIL)
- $$=label(hd[$1],$$),$1=tl[$1],
- $$=ap2(G_ALT,hd[$1],$$),$1=tl[$1];
- $$ = ap2(G_ERROR,$$,$3); };
- /* we right rotate G_ALT's to facilitate left factoring (see trans) */
-
-phrase1:
- term
- = { $$=cons($1,NIL); }|
- phrase1 '|' here term
- = { $$ = cons($4,cons($3,$1)); };
-
-term:
- count_factors
- = { word n=0,f=$1,rule=Void;
- /* default value of a production is () */
- /* rule=mkgvar(sreds); /* formerly last symbol */
- if(f!=NIL&&hd[f]==G_END)sreds++;
- if(ihlist)rule=ih_abstr(rule);
- while(n<sreds)rule=lambda(mkgvar(++n),rule);
- sreds=0;
- rule=ap(G_RULE,rule);
- while(f!=NIL)rule=ap2(G_SEQ,hd[f],rule),f=tl[f];
- $$ = rule; }|
- count_factors {inbnf=2;} indent '=' here rhs outdent
- = { if($1!=NIL&&hd[$1]==G_END)sreds++;
- if(sreds==1&&can_elide($6))
- inbnf=1,sreds=0,$$=hd[$1]; /* optimisation */
- else
- { word f=$1,rule=label($5,$6),n=0;
- inbnf=1;
- if(ihlist)rule=ih_abstr(rule);
- while(n<sreds)rule=lambda(mkgvar(++n),rule);
- sreds=0;
- rule=ap(G_RULE,rule);
- while(f!=NIL)rule=ap2(G_SEQ,hd[f],rule),f=tl[f];
- $$ = rule; }
- };
-
-error_term:
- ERRORSY
- = { word rule = ap(K,Void); /* default value of a production is () */
- if(ihlist)rule=ih_abstr(rule);
- $$ = rule; }|
- ERRORSY { inbnf=2,sreds=2; } indent '=' here rhs outdent
- = { word rule = label($5,$6);
- if(ihlist)rule=ih_abstr(rule);
- $$ = lambda(pair(mkgvar(1),mkgvar(2)),rule);
- inbnf=1,sreds=0; };
-
-count_factors:
- EMPTYSY
- = { sreds=0; $$=NIL; }|
- EMPTYSY factors
- = { syntax("unexpected token after empty\n");
- sreds=0; $$=NIL; }|
- { obrct=0; } factors
- = { word f=$2;
- if(obrct)
- syntax(obrct>0?"unmatched { in grammar rule\n":
- "unmatched } in grammar rule\n");
- for(sreds=0;f!=NIL;f=tl[f])sreds++;
- if(hd[$2]==G_END)sreds--;
- $$ = $2; };
-
-factors:
- factor
- = { $$ = cons($1,NIL); }|
- factors factor
- = { if(hd[$1]==G_END)
- syntax("unexpected token after end\n");
- $$ = cons($2,$1); };
-
-factor:
- unit|
- '{' unit '}'
- = { $$ = ap(outdent_fn,ap2(indent_fn,getcol_fn(),$2)); }|
- '{' unit
- = { obrct++;
- $$ = ap2(indent_fn,getcol_fn(),$2); }|
- unit '}'
- = { if(--obrct<0)syntax("unmatched `}' in grammar rule\n");
- $$ = ap(outdent_fn,$1); } ;
-
-unit:
- symbol|
- symbol '*'
- = { $$ = ap(G_STAR,$1); }|
- symbol '+'
- = { $$ = ap2(G_SEQ,$1,ap2(G_SEQ,ap(G_STAR,$1),ap(G_RULE,ap(C,P)))); }|
- symbol '?'
- = { $$ = ap(G_OPT,$1); };
-
-symbol:
- NAME
- = { extern word NEW;
- nonterminals=newadd1($1,nonterminals);
- if(NEW)ntmap=cons(cons($1,lasth),ntmap); }|
- ENDSY
- = { $$ = G_END; }|
- CONST
- = { if(!isstring($1))
- printf("%ssyntax error: illegal terminal ",echoing?"\n":""),
- out(stdout,$1),printf(" (should be string-const)\n"),
- acterror();
- $$ = ap(G_SYMB,$1); }|
- '^'
- = { $$=G_STATE; }|
- {inbnf=0;} '[' exp {inbnf=1;} ']'
- = { $$ = ap(G_SUCHTHAT,$3); }|
- '-'
- = { $$ = G_ANY; };
-
-%%
-/* end of MIRANDA RULES */
-
diff --git a/new/steer.c b/new/steer.c
deleted file mode 100644
index 27c238d..0000000
--- a/new/steer.c
+++ /dev/null
@@ -1,2208 +0,0 @@
-/* MIRANDA STEER */
-/* initialisation routines and assorted routines for I/O etc */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-/* this stuff is to get the time-last-modified of files */
-#include <sys/types.h>
-#include <sys/stat.h>
-/* #include <sys/wait.h> /* seems not needed, oct 05 */
-struct stat buf; /* see man(2) stat - gets file status */
-
-#include "data.h"
-#include "lex.h"
-#include <float.h>
-word nill,Void;
-word main_id; /* change to magic scripts 19.11.2013 */
-word message,standardout;
-word diagonalise,concat,indent_fn,outdent_fn,listdiff_fn;
-word shownum1,showbool,showchar,showlist,showstring,showparen,showpair,
- showvoid,showfunction,showabstract,showwhat;
-
-char PRELUDE[pnlim+10],STDENV[pnlim+9];
- /* if anyone complains, elasticate these buffers! */
-
-#define DFLTSPACE 2500000
-#define DFLTDICSPACE 100000
-/* default values for size of heap, dictionary */
-word SPACELIMIT=DFLTSPACE,DICSPACE=DFLTDICSPACE;
-
-#ifdef CYGWIN
-#define EDITOR "joe +!"
-#else
-#define EDITOR "vi +!"
-#endif
-/* The name of whatever is locally considered to be the default editor - the
- user will be able to override this using the `/editor' command.
- It is also overriden by shell/environment variable EDITOR if present */
-
-extern FILE *s_out;
-word UTF8=0, UTF8OUT=0;
-extern char *vdate, *host;
-extern word version, ND;
-
-char *mkabsolute(char *), *strvers(word);
-void fpe_error(void);
-
-char *editor=NULL;
-word okprel=0; /* set to 1 when prelude loaded */
-word nostdenv=0; /* if set to 1 mira does not load stdenv at startup */
-/* to allow a NOSTDENV directive _in_the_script_ we would need to
- (i) replace isltmess() test in rules by eg is this a list of thing,
- where thing is algebraic type originally defined in STDENV
- (ii) arrange to pick up <stdenv> when current script not loaded
- not implemented */
-word baded=0; /* see fixeditor() */
-char *miralib=NULL;
-char *mirahdr,*lmirahdr;
-char *promptstr="Miranda ";
-char *obsuffix="x";
-FILE *s_in=NULL;
-word commandmode=0; /* true only when reading command-level expressions */
-word atobject=0,atgc=0,atcount=0,debug=0;
-word magic=0; /* set to 1 means script will start with UNIX magic string */
-word making=0; /* set only for mira -make */
-word mkexports=0; /* set only for mira -exports */
-word mksources=0; /* set only for mira -sources */
-word make_status=0; /* exit status of -make */
-word compiling=1;
-/* there are two types of MIRANDA process - compiling (the main process) and
-subsidiary processes launched for each evaluation - the above flag tells
-us which kind of process we are in */
-word ideep=0; /* depth of %include we are at, see mkincludes() */
-word SYNERR=0;
-word initialising=1;
-word primenv=NIL;
-char *current_script;
-word lastexp=UNDEF; /* value of `$$' */
-word echoing=0,listing=0,verbosity;
-word strictif=1,rechecking=0;
-word errline=0; /* records position of last error, for editor */
-word errs=0; /* secondary error location, in inserted script, if relevant */
-word *cstack;
-extern word c;
-extern char *dicp,*dicq;
-char linebuf[BUFSIZE]; /* used for assorted purposes */
- /* NB cannot share with linebuf in lex.c, or !! goes wrong */
-static char ebuf[pnlim];
-word col;
-char home_rc[pnlim+8];
-char lib_rc[pnlim+8];
-char *rc_error=NULL;
-#define badval(x) (x<1||x>478000000)
-
-#include <setjmp.h> /* for longjmp() - see man (3) setjmp */
-jmp_buf env;
-
-#ifdef sparc8
-#include <ieeefp.h>
-fp_except commonmask = FP_X_INV|FP_X_OFL|FP_X_DZ; /* invalid|ovflo|divzero */
-#endif
-
-main(argc,argv) /* system initialisation, followed by call to YACC */
-word argc;
-char *argv[];
-{ word manonly=0;
- char *home, *prs;
- word okhome_rc; /* flags valid HOME/.mirarc file present */
- char *argv0=argv[0];
- char *initscript;
- word badlib=0;
- extern word ARGC; extern char **ARGV;
- extern word newtyps,algshfns;
- char *progname=rindex(argv[0],'/');
- cstack= &manonly;
-/* used to indicate the base of the C stack for garbage collection purposes */
- verbosity=isatty(0);
-/*if(isatty(1))*/ setbuf(stdout,NULL); /* for unbuffered tty output */
- if(home=getenv("HOME"))
- { strcpy(home_rc,home);
- if(strcmp(home_rc,"/")==0)home_rc[0]=0; /* root is special case */
- strcat(home_rc,"/.mirarc");
- okhome_rc=rc_read(home_rc); }
-/*setup policy:
- if valid HOME/.mirarc found look no further, otherwise try
- <miralib>/.mirarc
- Complaints - if any .mirarc contained bad data, `announce' complains about
- the last such looked at. */
- UTF8OUT=UTF8=utf8test();
- while(argc>1&&argv[1][0]=='-') /* strip off flags */
- { if(strcmp(argv[1],"-stdenv")==0)nostdenv=1; else
- if(strcmp(argv[1],"-count")==0)atcount=1; else
- if(strcmp(argv[1],"-list")==0)listing=1; else
- if(strcmp(argv[1],"-nolist")==0)listing=0; else
- if(strcmp(argv[1],"-nostrictif")==0)strictif=0; else
- if(strcmp(argv[1],"-gc")==0)atgc=1; else
- if(strcmp(argv[1],"-object")==0)atobject=1; else
- if(strcmp(argv[1],"-lib")==0)
- { argc--,argv++;
- if(argc==1)missparam("lib"); else miralib=argv[1];
- } else
- if(strcmp(argv[1],"-dic")==0)
- { argc--,argv++;
- if(argc==1)missparam("dic"); else
- if(sscanf(argv[1],"%d",&DICSPACE)!=1||badval(DICSPACE))
- fprintf(stderr,"mira: bad value after flag \"-dic\"\n"),exit(1);
- } else
- if(strcmp(argv[1],"-heap")==0)
- { argc--,argv++;
- if(argc==1)missparam("heap"); else
- if(sscanf(argv[1],"%d",&SPACELIMIT)!=1||badval(SPACELIMIT))
- fprintf(stderr,"mira: bad value after flag \"-heap\"\n"),exit(1);
- } else
- if(strcmp(argv[1],"-editor")==0)
- { argc--,argv++;
- if(argc==1)missparam("editor");
- else editor=argv[1],fixeditor();
- } else
- if(strcmp(argv[1],"-hush")==0)verbosity=0; else
- if(strcmp(argv[1],"-nohush")==0)verbosity=1; else
- if(strcmp(argv[1],"-exp")==0||strcmp(argv[1],"-log")==0)
- fprintf(stderr,"mira: obsolete flag \"%s\"\n"
- "use \"-exec\" or \"-exec2\", see manual\n",
- argv[1]),exit(1); else
- if(strcmp(argv[1],"-exec")==0) /* replaces -exp 26.11.2019 */
- ARGC=argc-2,ARGV=argv+2,magic=1,verbosity=0; else
- if(strcmp(argv[1],"-exec2")==0) /* version of -exec for debugging CGI scripts */
- { if(argc<=2)fprintf(stderr,"incorrect use of -exec2 flag, missing filename\n"),exit(1);
- char *logfilname, *p=strrchr(argv[2],'/');
- FILE *fil=NULL;
- if(!p)p=argv[2]; /* p now holds last component of prog name */
- if(logfilname=malloc((strlen(p)+9)))
- sprintf(logfilname,"miralog/%s",p),
- fil=fopen(logfilname,"a");
- else mallocfail("logfile name");
- /* process requires write permission on local directory "miralog" */
- if(fil)dup2(fileno(fil),2); /* redirect stderr to log file */
- else fprintf(stderr,"could not open %s\n",logfilname);
- ARGC=argc-2,ARGV=argv+2,magic=1,verbosity=0; } else
- if(strcmp(argv[1],"-man")==0){ manonly=1; break; } else
- if(strcmp(argv[1],"-version")==0)v_info(0),exit(0); else
- if(strcmp(argv[1],"-V")==0)v_info(1),exit(0); else
- if(strcmp(argv[1],"-make")==0) making=1,verbosity=0; else
- if(strcmp(argv[1],"-exports")==0) making=mkexports=1,verbosity=0; else
- if(strcmp(argv[1],"-sources")==0) making=mksources=1,verbosity=0; else
- if(strcmp(argv[1],"-UTF-8")==0) UTF8=1; else
- if(strcmp(argv[1],"-noUTF-8")==0) UTF8=0; else
- fprintf(stderr,"mira: unknown flag \"%s\"\n",argv[1]),exit(1);
- argc--,argv++; }
- if(argc>2&&!magic&&!making)fprintf(stderr,"mira: too many args\n"),exit(1);
- if(!miralib) /* no -lib flag */
- { char *m;
- /* note search order */
- if((m=getenv("MIRALIB")))miralib=m; else
- if(checkversion(m="/usr/lib/miralib"))miralib=m; else
- if(checkversion(m="/usr/local/lib/miralib"))miralib=m; else
- if(checkversion(m="miralib"))miralib=m; else
- badlib=1;
- }
- if(badlib)
- { fprintf(stderr,"fatal error: miralib version %s not found\n",
- strvers(version));
- libfails();
- exit(1);
- }
- if(!okhome_rc)
- { if(rc_error==lib_rc)rc_error=NULL;
- (void)strcpy(lib_rc,miralib);
- (void)strcat(lib_rc,"/.mirarc");
- rc_read(lib_rc); }
- if(editor==NULL) /* .mirarc was absent or unreadable */
- { editor=getenv("EDITOR");
- if(editor==NULL)editor=EDITOR;
- else strcpy(ebuf,editor),editor=ebuf,fixeditor(); }
- if(prs=getenv("MIRAPROMPT"))promptstr=prs;
- if(getenv("RECHECKMIRA")&&!rechecking)rechecking=1;
- if(getenv("NOSTRICTIF"))strictif=0;
- setupdic(); /* used by mkabsolute */
- s_in=stdin;
- s_out=stdout;
- miralib=mkabsolute(miralib); /* protection against "/cd" */
- if(manonly)manaction(),exit(0);
- (void)strcpy(PRELUDE,miralib); (void)strcat(PRELUDE,"/prelude");
- /* convention - change spelling of "prelude" at each release */
- (void)strcpy(STDENV,miralib);
- (void)strcat(STDENV,"/stdenv.m");
- mira_setup();
- if(verbosity)announce();
- files=NIL;
- undump(PRELUDE),okprel=1;
- mkprivate(fil_defs(hd[files]));
- files=NIL; /* don't wish unload() to unsetids on prelude */
- if(!nostdenv)
- { undump(STDENV);
- while(files!=NIL) /* stdenv may have %include structure */
- primenv=alfasort(append1(primenv,fil_defs(hd[files]))),
- files=tl[files];
- primenv=alfasort(primenv);
- newtyps=files=NIL; /* don't wish unload() to unsetids */ }
- if(!magic)rc_write();
- echoing = verbosity&listing;
- initialising=0;
- if(mkexports)
- { /* making=1, to say if recompiling, also to undump as for %include */
- word f,argcount=argc-1;
- extern word exports,freeids;
- char *s;
- setjmp(env); /* will return here on blankerr (via reset) */
- while(--argc) /* where do error messages go?? */
- { word x=NIL;
- s=addextn(1,*++argv);
- if(s==dicp)keep(dicp);
- undump(s); /* bug, recompile messages goto stdout - FIX LATER */
- if(files==NIL||ND!=NIL)continue;
- if(argcount!=1)printf("%s\n",s);
- if(exports!=NIL)x=exports;
- /* true (if ever) only if just recompiled */
- else for(f=files;f!=NIL;f=tl[f])x=append1(fil_defs(hd[f]),x);
- /* method very clumsy, because exports not saved in dump */
- if(freeids!=NIL)
- { word f=freeids;
- while(f!=NIL)
- { word n=findid((char *)hd[hd[tl[hd[f]]]]);
- id_type(n)=tl[tl[hd[f]]];
- id_val(n)=the_val(hd[hd[f]]);
- hd[f]=n;
- f=tl[f]; }
- f=freeids=typesfirst(freeids);
- printf("\t%%free {\n");
- while(f!=NIL)
- putchar('\t'),
- report_type(hd[f]),
- putchar('\n'),
- f=tl[f];
- printf("\t}\n"); }
- for(x=typesfirst(alfasort(x));x!=NIL;x=tl[x])
- { putchar('\t');
- report_type(hd[x]);
- putchar('\n'); } }
- exit(0); }
- if(mksources){ extern word oldfiles;
- char *s;
- word f,x=NIL;
- setjmp(env); /* will return here on blankerr (via reset) */
- while(--argc)
- if(stat((s=addextn(1,*++argv)),&buf)==0)
- { if(s==dicp)keep(dicp);
- undump(s);
- for(f=files==NIL?oldfiles:files;f!=NIL;f=tl[f])
- if(!member(x,(word)get_fil(hd[f])))
- x=cons((word)get_fil(hd[f]),x),
- printf("%s\n",get_fil(hd[f]));
- }
- exit(0); }
- if(making){ extern word oldfiles;
- char *s;
- setjmp(env); /* will return here on blankerr (via reset) */
- while(--argc) /* where do error messages go?? */
- { s=addextn(1,*++argv);
- if(s==dicp)keep(dicp);
- undump(s);
- if(ND!=NIL||files==NIL&&oldfiles!=NIL)
- { if(make_status==1)make_status=0;
- make_status=strcons(s,make_status); }
- /* keep list of source files with error-dumps */
- }
- if(tag[make_status]==STRCONS)
- { word h=0,maxw=0,w,n;
- printf("errors or undefined names found in:-\n");
- while(make_status) /* reverse to get original order */
- { h=strcons(hd[make_status],h);
- w=strlen((char *)hd[h]);
- if(w>maxw)maxw=w;
- make_status=tl[make_status]; }
- maxw++;n=78/maxw;w=0;
- while(h)
- printf("%*s%s",maxw,(char *)hd[h],(++w%n)?"":"\n"),
- h=tl[h];
- if(w%n)printf("\n");
- make_status=1; }
- exit(make_status); }
- initscript= argc==1?"script.m":magic?argv[1]:addextn(1,argv[1]);
- if(initscript==dicp)keep(dicp);
-#if sparc8
- fpsetmask(commonmask);
-#elif defined sparc
- ieee_handler("set","common",(sighandler)fpe_error);
-#endif
-#if !defined sparc | sparc8
- (void)signal(SIGFPE,(sighandler)fpe_error); /* catch arithmetic overflow */
-#endif
- (void)signal(SIGTERM,(sighandler)exit); /* flush buffers if killed */
- commandloop(initscript);
- /* parameter is file given as argument */
-}
-
-word vstack[4]; /* record of miralib versions looked at */
-char *mstack[4]; /* and where found */
-word mvp=0;
-
-checkversion(m)
-/* returns 1 iff m is directory with .version containing our version number */
-char *m;
-{ word v1,read=0,r=0;
- FILE *f=fopen(strcat(strcpy(linebuf,m),"/.version"),"r");
- if(f&&fscanf(f,"%u",&v1)==1)r= v1==version, read=1;
- if(f)fclose(f);
- if(read&&!r)mstack[mvp]=m,vstack[mvp++]=v1;
- return r;
-}
-
-libfails()
-{ word i=0;
- fprintf(stderr,"found");
- for(;i<mvp;i++)fprintf(stderr,"\tversion %s at: %s\n",
- strvers(vstack[i]),mstack[i]);
-}
-
-char *strvers(v)
-{ static char vbuf[12];
- if(v<0||v>999999)return "\?\?\?";
- snprintf(vbuf,12,"%.3f",v/1000.0);
- return vbuf;
-}
-
-char *mkabsolute(m) /* make sure m is an absolute pathname */
-char *m;
-{ if(m[0]=='/')return(m);
- if(!getcwd(dicp,pnlim))fprintf(stderr,"panic: cwd too long\n"),exit(1);
- (void)strcat(dicp,"/");
- (void)strcat(dicp,m);
- m=dicp;
- dicp=dicq+=strlen(dicp)+1;
- dic_check();
- return(m);
-}
-
-missparam(s)
-char *s;
-{ fprintf(stderr,"mira: missing param after flag \"-%s\"\n",s);
- exit(1); }
-
-word oldversion=0;
-#define colmax 400
-#define spaces(s) for(j=s;j>0;j--)putchar(' ')
-
-announce()
-{ extern char *vdate;
- word w,j;
-/*clrscr(); /* clear screen on start up */
- w=(twidth()-50)/2;
- printf("\n\n");
- spaces(w); printf(" T h e M i r a n d a S y s t e m\n\n");
- spaces(w+5-strlen(vdate)/2);
- printf(" version %s last revised %s\n\n",strvers(version),vdate);
- spaces(w); printf("Copyright Research Software Ltd 1985-2019\n\n");
- spaces(w); printf(" World Wide Web: http://miranda.org.uk\n\n\n");
- if(SPACELIMIT!=DFLTSPACE)
- printf("(%d cells)\n",SPACELIMIT);
- if(!strictif)printf("(-nostrictif : deprecated!)\n");
-/*printf("\t\t\t\t%dbit platform\n",__WORDSIZE); /* */
- if(oldversion<1999) /* pre release two */
- printf("\
-WARNING:\n\
-a new release of Miranda has been installed since you last used\n\
-the system - please read the `CHANGES' section of the /man pages !!!\n\n");
- else
- if(version>oldversion)
- printf("a new version of Miranda has been installed since you last\n"),
- printf("used the system - see under `CHANGES' in the /man pages\n\n");
- if(version<oldversion)
- printf("warning - this is an older version of Miranda than the one\n"),
- printf("you last used on this machine!!\n\n");
- if(rc_error)
- printf("warning: \"%s\" contained bad data (ignored)\n",rc_error);
-}
-
-
-rc_read(rcfile) /* get settings of system parameters from setup file */
-char *rcfile;
-{ FILE *in;
- char z[20];
- word h,d,v,s,r=0;
- oldversion=version; /* default assumption */
- in=fopen(rcfile,"r");
- if(in==NULL||fscanf(in,"%19s",z)!=1)
- return(0); /* file not present, or not readable */
- if(strncmp(z,"hdve",4)==0 /* current .mirarc format */
- ||strcmp(z,"lhdve")==0) /* alternative format used at release one */
- { char *z1 = &z[3];
- if(z[0]=='l')listing=1,z1++;
- while(*++z1)if(*z1=='l')listing=1; else
- if(*z1=='s') /* ignore */; else
- if(*z1=='r')rechecking=2; else
- rc_error=rcfile;
- if(fscanf(in,"%d%d%d%*c",&h,&d,&v)!=3||!getln(in,pnlim-1,ebuf)
- ||badval(h)||badval(d)||badval(v))rc_error=rcfile;
- else editor=ebuf,SPACELIMIT=h,DICSPACE=d,r=1,
- oldversion=v; } else
- if(strcmp(z,"ehdsv")==0) /* versions before 550 */
- { if(fscanf(in,"%19s%d%d%d%d",ebuf,&h,&d,&s,&v)!=5
- ||badval(h)||badval(d)||badval(v))rc_error=rcfile;
- else editor=ebuf,SPACELIMIT=h,DICSPACE=d,r=1,
- oldversion=v; } else
- if(strcmp(z,"ehds")==0) /* versions before 326, "s" was stacklimit (ignore) */
- { if(fscanf(in,"%s%d%d%d",ebuf,&h,&d,&s)!=4
- ||badval(h)||badval(d))rc_error=rcfile;
- else editor=ebuf,SPACELIMIT=h,DICSPACE=d,r=1,
- oldversion=1; }
- else rc_error=rcfile; /* unrecognised format */
- if(editor)fixeditor();
- fclose(in);
- return(r);
-}
-
-fixeditor()
-{ if(strcmp(editor,"vi")==0)editor="vi +!"; else
- if(strcmp(editor,"pico")==0)editor="pico +!"; else
- if(strcmp(editor,"nano")==0)editor="nano +!"; else
- if(strcmp(editor,"joe")==0)editor="joe +!"; else
- if(strcmp(editor,"jpico")==0)editor="jpico +!"; else
- if(strcmp(editor,"vim")==0)editor="vim +!"; else
- if(strcmp(editor,"gvim")==0)editor="gvim +! % &"; else
- if(strcmp(editor,"emacs")==0)editor="emacs +! % &";
- else { char *p=rindex(editor,'/');
- if(p==0)p=editor; else p++;
- if(strcmp(p,"vi")==0)strcat(p," +!");
- }
- if(rindex(editor,'&'))rechecking=2;
- listing=badeditor();
-}
-
-badeditor() /* does editor know how to open file at line? */
-{ char *p=index(editor,'!');
- while(p&&p[-1]=='\\')p=index(p+1,'!');
- return (baded = !p);
-}
-
-getln(in,n,s) /* reads line (<=n chars) from in into s - returns 1 if ok */
-FILE *in; /* the newline is discarded, and the result '\0' terminated */
-word n;
-char *s;
-{ while(n--&&(*s=getc(in))!='\n')s++;
- if(*s!='\n'||n<0)return(0);
- *s='\0';
- return(1);
-} /* what a pain that `fgets' doesn't do it right !! */
-
-rc_write()
-{ FILE *out=fopen(home_rc,"w");
- if(out==NULL)
- { fprintf(stderr,"warning: cannot write to \"%s\"\n",home_rc);
- return; }
- fprintf(out,"hdve");
- if(listing)fputc('l',out);
- if(rechecking==2)fputc('r',out);
- fprintf(out," %d %d %d %s\n",SPACELIMIT,DICSPACE,version,editor);
- fclose(out);
-}
-
-word lastid=0; /* first inscope identifier of immediately preceding command */
-word rv_expr=0;
-
-commandloop(initscript)
-char* initscript;
-{ word ch;
- word reset();
- extern word cook_stdin,polyshowerror;
- char *lb;
- if(setjmp(env)==0) /* returns here if interrupted, 0 means first time thru */
- { if(magic){ undump(initscript); /* was loadfile() changed 26.11.2019
- to allow dump of magic scripts in ".m"*/
- if(files==NIL||ND!=NIL||id_val(main_id)==UNDEF)
- /* files==NIL=>script absent or has syntax errors
- ND!=NIL=>script has type errors or undefined names
- all reported by undump() or loadfile() on new compile */
- { if(files!=NIL&&ND==NIL&&id_val(main_id)==UNDEF)
- fprintf(stderr,"%s: main not defined\n",initscript);
- fprintf(stderr,"mira: incorrect use of \"-exec\" flag\n");
- exit(1); }
- magic=0; obey(main_id); exit(0); }
- /* was obey(lastexp), change to magic scripts 19.11.2013 */
- (void)signal(SIGINT,(sighandler)reset);
- undump(initscript);
- if(verbosity)printf("for help type /h\n"); }
- for(;;)
- { resetgcstats();
- if(verbosity)printf("%s",promptstr);
- ch = getchar();
- if(rechecking&&src_update())loadfile(current_script);
- /* modified behaviour for `2-window' mode */
- while(ch==' '||ch=='\t')ch=getchar();
- switch(ch)
- { case '?': ch=getchar();
- if(ch=='?')
- { word x; char *aka=NULL;
- if(!token()&&!lastid)
- { printf("\7identifier needed after `\?\?'\n");
- ch=getchar(); /* '\n' */
- break; }
- if(getchar()!='\n'){ xschars(); break; }
- if(baded){ ed_warn(); break; }
- if(dicp[0])x=findid(dicp);
- else printf("??%s\n",get_id(lastid)),x=lastid;
- if(x==NIL||id_type(x)==undef_t)
- { diagnose(dicp[0]?dicp:get_id(lastid));
- lastid=0;
- break; }
- if(id_who(x)==NIL)
- { /* nb - primitives have NIL who field */
- printf("%s -- primitive to Miranda\n",
- dicp[0]?dicp:get_id(lastid));
- lastid=0;
- break; }
- lastid=x;
- x=id_who(x); /* get here info */
- if(tag[x]==CONS)aka=(char *)hd[hd[x]],x=tl[x];
- if(aka)printf("originally defined as \"%s\"\n",
- aka);
- editfile((char *)hd[x],tl[x]);
- break; }
- ungetc(ch,stdin);
- (void)token();
- lastid=0;
- if(dicp[0]=='\0')
- { if(getchar()!='\n')xschars();
- else allnamescom();
- break; }
- while(dicp[0])finger(dicp),(void)token();
- ch=getchar();
- break;
- case ':': /* add (silently) as kindness to Hugs users */
- case '/': (void)token();
- lastid=0;
- command(ch);
- break;
- case '!': if(!(lb=rdline()))break; /* rdline returns NULL on failure */
- lastid=0;
- if(*lb)
- { /*system(lb); */ /* always gives /bin/sh */
- static char *shell=NULL;
- sighandler oldsig;
- word pid;
- if(!shell)
- { shell=getenv("SHELL");
- if(!shell)shell="/bin/sh"; }
- oldsig= signal(SIGINT,SIG_IGN);
- if(pid=fork())
- { /* parent */
- if(pid==-1)
- perror("UNIX error - cannot create process");
- while(pid!=wait(0));
- (void)signal(SIGINT,oldsig); }
- else execl(shell,shell,"-c",lb,(char *)0);
- if(src_update())loadfile(current_script); }
- else printf(
- "No previous shell command to substitute for \"!\"\n");
- break;
- case '|': /* lines beginning "||" are comments */
- if((ch=getchar())!='|')
- printf("\7unknown command - type /h for help\n");
- while(ch!='\n'&&ch!=EOF)ch=getchar();
- case '\n': break;
- case EOF: if(verbosity)printf("\nmiranda logout\n");
- exit(0);
- default: ungetc(ch,stdin);
- lastid=0;
- tl[hd[cook_stdin]]=0; /* unset type of $+ */
- rv_expr=0;
- c = EVAL;
- echoing=0;
- polyshowerror=0; /* gets set by wrong use of $+, readvals */
- commandmode=1;
- yyparse();
- if(SYNERR)SYNERR=0;
- else if(c!='\n') /* APPARENTLY NEVER TRUE */
- { printf("syntax error\n");
- while(c!='\n'&&c!=EOF)
- c=getchar(); /* swallow syntax errors */
- }
- commandmode=0;
- echoing=verbosity&listing;
-}}}
-
-parseline(t,f,fil) /* parses next valid line of f at type t, returns EOF
- if none found. See READVALS in reduce.c */
-word t;
-FILE *f;
-word fil;
-{ word t1,ch;
- lastexp=UNDEF;
- for(;;)
- { ch=getc(f);
- while(ch==' '||ch=='\t'||ch=='\n')ch=getc(f);
- if(ch=='|')
- { ch=getc(f);
- if(ch=='|') /* leading comment */
- { while((ch=getc(f))!='\n'&&ch!=EOF);
- if(ch!=EOF)continue; }
- else ungetc(ch,f); }
- if(ch==EOF)return(EOF);
- ungetc(ch,f);
- c = VALUE;
- echoing=0;
- commandmode=1;
- s_in=f;
- yyparse();
- s_in=stdin;
- if(SYNERR)SYNERR=0,lastexp=UNDEF; else
- if((t1=type_of(lastexp))==wrong_t)lastexp=UNDEF; else
- if(!subsumes(instantiate(t1),t))
- { printf("data has wrong type :: "), out_type(t1),
- printf("\nshould be :: "), out_type(t), putc('\n',stdout);
- lastexp=UNDEF; }
- if(lastexp!=UNDEF)return(codegen(lastexp));
- if(isatty(fileno(f)))printf("please re-enter data:\n");
- else { if(fil)fprintf(stderr,"readvals: bad data in file \"%s\"\n",
- getstring(fil,0));
- else fprintf(stderr,"bad data in $+ input\n");
- outstats(); exit(1); }
-}}
-
-ed_warn()
-{ printf(
-"The currently installed editor command, \"%s\", does not\n\
-include a facility for opening a file at a specified line number. As a\n\
-result the `\?\?' command and certain other features of the Miranda system\n\
-are disabled. See manual section 31/5 on changing the editor for more\n\
-information.\n",editor);
-}
-
-time_t fm_time(f) /* time last modified of file f */
-char *f;
-{ return(stat(f,&buf)==0?buf.st_mtime:0);
- /* non-existent file has conventional mtime of 0 */
-} /* WARNING - we assume time_t can be stored in an int field
- - this may not port */
-
-#define same_file(x,y) (hd[fil_inodev(x)]==hd[fil_inodev(y)]&& \
- tl[fil_inodev(x)]==tl[fil_inodev(y)])
-#define inodev(f) (stat(f,&buf)==0?datapair(buf.st_ino,buf.st_dev):\
- datapair(0,-1))
-
-word oldfiles=NIL; /* most recent set of sources, in case of interrupted or
- failed compilation */
-src_update() /* any sources modified ? */
-{ word ft,f=files==NIL?oldfiles:files;
- while(f!=NIL)
- { if((ft=fm_time(get_fil(hd[f])))!=fil_time(hd[f]))
- { if(ft==0)unlinkx(get_fil(hd[f])); /* tidy up after eg `!rm %' */
- return(1); }
- f=tl[f]; }
- return(0);
-}
-
-word loading;
-char *unlinkme; /* if set, is name of partially created obfile */
-
-reset() /* interrupt catcher - see call to signal in commandloop */
-{ extern word lineptr,ATNAMES,current_id;
- extern word blankerr,collecting/* ,*dstack,*stackp */;
- /*if(!making) /* see note below
- (void)signal(SIGINT,SIG_IGN); /* dont interrupt me while I'm tidying up */
-/*if(magic)exit(0); *//* signal now not set to reset in magic scripts */
- if(collecting)gcpatch();
- if(loading)
- { if(!blankerr)
- printf("\n<<compilation interrupted>>\n");
- if(unlinkme)unlink(unlinkme);
- /* stackp=dstack; /* add if undump() made interruptible later*/
- oldfiles=files,unload(),current_id=ATNAMES=loading=SYNERR=lineptr=0;
- if(blankerr)blankerr=0,makedump(); }
- /* magic script cannot be literate so no guard needed on makedump */
- else printf("<<interrupt>>\n"); /* VAX, SUN, ^C does not cause newline */
- reset_state(); /* see LEX */
- if(collecting)collecting=0,gc(); /* to mark stdenv etc as wanted */
- if(making&&!make_status)make_status=1;
-#ifdef SYSTEM5
- else (void)signal(SIGINT,(sighandler)reset);/*ready for next interrupt*//*see note*/
-#endif
- /* during mira -make blankerr is only use of reset */
- longjmp(env,1);
-}/* under BSD and Linux installed signal remains installed after interrupt
- and further signals blocked until handler returns */
-
-#define checkeol if(getchar()!='\n')break;
-
-word lose;
-
-normal(f) /* s has ".m" suffix */
-char *f;
-{ word n=strlen(f);
- return n>=2&&strcmp(f+n-2,".m")==0;
-}
-
-v_info(word full)
-{ printf("%s last revised %s\n",strvers(version),vdate);
- if(!full)return;
- printf("%s",host);
- printf("XVERSION %u\n",XVERSION);
-}
-
-
-command(c)
-word c;
-{ char *t;
- word ch,ch1;
- switch(dicp[0])
- {
- case 'a': if(is("a")||is("aux"))
- { checkeol;
-/* if(verbosity)clrscr(); */
- (void)strcpy(linebuf,miralib);
- (void)strcat(linebuf,"/auxfile");
- filecopy(linebuf);
- return; }
- case 'c': if(is("count"))
- { checkeol; atcount=1; return; }
- if(is("cd"))
- { char *d=token();
- if(!d)d=getenv("HOME");
- else d=addextn(0,d);
- checkeol;
- if(chdir(d)==-1)printf("cannot cd to %s\n",d);
- else if(src_update())undump(current_script);
- /* alternative: keep old script and recompute pathname
- wrt new directory - LOOK INTO THIS LATER */
- return; }
- case 'd': if(is("dic"))
- { extern char *dic;
- if(!token())
- { lose=getchar(); /* to eat \n */
- printf("%d chars",DICSPACE);
- if(DICSPACE!=DFLTDICSPACE)
- printf(" (default=%d)",DFLTDICSPACE);
- printf(" %d in use\n",dicq-dic);
- return; }
- checkeol;
- printf(
- "sorry, cannot change size of dictionary while in use\n");
- printf(
- "(/q and reinvoke with flag: mira -dic %s ... )\n",dicp);
- return; }
- case 'e': if(is("e")||is("edit"))
- { char *mf=0;
- if(t=token())t=addextn(1,t);
- else t=current_script;
- checkeol;
- if(stat(t,&buf)) /* new file */
- { if(!lmirahdr) /* lazy initialisation */
- { dicp=dicq;
- (void)strcpy(dicp,getenv("HOME"));
- if(strcmp(dicp,"/")==0)
- dicp[0]=0; /* root is special case */
- (void)strcat(dicp,"/.mirahdr");
- lmirahdr=dicp;
- dicq=dicp=dicp+strlen(dicp)+1; } /* ovflo check? */
- if(!stat(lmirahdr,&buf))mf=lmirahdr;
- if(!mf&&!mirahdr) /* lazy initialisation */
- { dicp=dicq;
- (void)strcpy(dicp,miralib);
- (void)strcat(dicp,"/.mirahdr");
- mirahdr=dicp;
- dicq=dicp=dicp+strlen(dicp)+1; }
- if(!mf&&!stat(mirahdr,&buf))mf=mirahdr;
- /*if(mf)printf("mf=%s\n",mf); /* DEBUG*/
- if(mf&&t!=current_script)
- { printf("open new script \"%s\"? [ny]",t);
- ch1=ch=getchar();
- while(ch!='\n'&&ch!=EOF)ch=getchar();
- /*eat rest of line */
- if(ch1!='y'&&ch1!='Y')return; }
- if(mf)filecp(mf,t); }
- editfile(t,strcmp(t,current_script)==0?errline:
- errs&&strcmp(t,(char *)hd[errs])==0?tl[errs]:
- geterrlin(t));
- return; }
- if(is("editor"))
- { char *hold=linebuf,*h;
- if(!getln(stdin,pnlim-1,hold))break; /*reject if too long*/
- if(!*hold)
- { /* lose=getchar(); /* to eat newline */
- printf("%s\n",editor);
- return; }
- h=hold+strlen(hold); /* remove trailing white space */
- while(h[-1]==' '||h[-1]=='\t')*--h='\0';
- if(*hold=='"'||*hold=='\'')
- { printf("please type name of editor without quotation marks\n");
- return; }
- printf("change editor to: \"%s\"? [ny]",hold);
- ch1=ch=getchar();
- while(ch!='\n'&&ch!=EOF)ch=getchar(); /* eat rest of line */
- if(ch1!='y'&&ch1!='Y')
- { printf("editor not changed\n");
- return; }
- (void)strcpy(ebuf,hold);
- editor=ebuf;
- fixeditor(); /* reads "vi" as "vi +!" etc */
- echoing=verbosity&listing;
- rc_write();
- printf("editor = %s\n",editor);
- return; }
- case 'f': if(is("f")||is("file"))
- { char *t=token();
- checkeol;
- if(t)t=addextn(1,t),keep(t);
- /* could get multiple copies of filename in dictionary
- - FIX LATER */
- if(t)errs=errline=0; /* moved here from reset() */
- if(t)if(strcmp(t,current_script)||files==NIL&&okdump(t))
- { extern word CLASHES;
- CLASHES=NIL; /* normally done by load_script */
- undump(t); /* does not always call load_script */
- if(CLASHES!=NIL)/* pathological case, recompile */
- loadfile(t); }
- else loadfile(t); /* force recompilation */
- else printf("%s%s\n",current_script,
- files==NIL?" (not loaded)":"");
- return; }
- if(is("files")) /* info about internal state, not documented */
- { word f=files;
- checkeol;
- for(;f!=NIL;f=tl[f])
- printf("(%s,%d,%d)",get_fil(hd[f]),fil_time(hd[f]),
- fil_share(hd[f])),printlist("",fil_defs(hd[f]));
- return; } /* DEBUG */
- if(is("find"))
- { word i=0;
- while(token())
- { word x=findid(dicp),y,f;
- i++;
- if(x!=NIL)
- { char *n=get_id(x);
- for(y=primenv;y!=NIL;y=tl[y])
- if(tag[hd[y]]==ID)
- if(hd[y]==x||getaka(hd[y])==n)
- finger(get_id(hd[y]));
- for(f=files;f!=NIL;f=tl[f])
- for(y=fil_defs(hd[f]);y!=NIL;y=tl[y])
- if(tag[hd[y]]==ID)
- if(hd[y]==x||getaka(hd[y])==n)
- finger(get_id(hd[y])); }
- }
- ch=getchar(); /* '\n' */
- if(i==0)printf("\7identifier needed after `/find'\n");
- return; }
- case 'g': if(is("gc"))
- { checkeol; atgc=1; return; }
- case 'h': if(is("h")||is("help"))
- { checkeol;
-/* if(verbosity)clrscr(); */
- (void)strcpy(linebuf,miralib);
- (void)strcat(linebuf,"/helpfile");
- filecopy(linebuf);
- return; }
- if(is("heap"))
- { word x;
- if(!token())
- { lose=getchar(); /* to eat \n */
- printf("%d cells",SPACELIMIT);
- if(SPACELIMIT!=DFLTSPACE)
- printf(" (default=%d)",DFLTSPACE);
- printf("\n");
- return; }
- checkeol;
- if(sscanf(dicp,"%d",&x)!=1||badval(x))
- { printf("illegal value (heap unchanged)\n"); return; }
- if(x<trueheapsize())
- printf("sorry, cannot shrink heap to %d at this time\n",x);
- else { if(x!=SPACELIMIT)
- SPACELIMIT=x,resetheap();
- printf("heaplimit = %d cells\n",SPACELIMIT),
- rc_write(); }
- return; }
- if(is("hush"))
- { checkeol; echoing=verbosity=0; return; }
- case 'l': if(is("list"))
- { checkeol; listing=1; echoing=verbosity&listing;
- rc_write(); return; }
- case 'm': if(is("m")||is("man"))
- { checkeol; manaction(); return; }
- if(is("miralib"))
- { checkeol; printf("%s\n",miralib); return; }
- case 'n': /* if(is("namebuckets"))
- { int i,x;
- extern int namebucket[];
- checkeol;
- for(i=0;i<128;i++)
- if(x=namebucket[i])
- { printf("%d:",i);
- while(x)
- putchar(' '),out(stdout,hd[x]),x=tl[x];
- putchar('\n'); }
- return; } /* DEBUG */
- if(is("nocount"))
- { checkeol; atcount=0; return; }
- if(is("nogc"))
- { checkeol; atgc=0; return; }
- if(is("nohush"))
- { checkeol; echoing=listing; verbosity=1; return; }
- if(is("nolist"))
- { checkeol; echoing=listing=0; rc_write(); return; }
- if(is("norecheck"))
- { checkeol; rechecking=0; rc_write(); return; }
-/* case 'o': if(is("object"))
- { checkeol; atobject=1; return; } /* now done by flag -object */
- case 'q': if(is("q")||is("quit"))
- { checkeol; if(verbosity)printf("miranda logout\n"); exit(0); }
- case 'r': if(is("recheck"))
- { checkeol; rechecking=2; rc_write(); return; }
- case 's': if(is("s")||is("settings"))
- { checkeol;
- printf("*\theap %d\n",SPACELIMIT);
- printf("*\tdic %d\n",DICSPACE);
- printf("*\teditor = %s\n",editor);
- printf("*\t%slist\n",listing?"":"no");
- printf("*\t%srecheck\n",rechecking?"":"no");
- if(!strictif)
- printf("\t-nostrictif (deprecated!)\n");
- if(atcount)printf("\tcount\n");
- if(atgc)printf("\tgc\n");
- if(UTF8)printf("\tUTF-8 i/o\n");
- if(!verbosity)printf("\thush\n");
- if(debug)printf("\tdebug 0%o\n",debug);
- printf("\n* items remembered between sessions\n");
- return; }
- case 'v': if(is("v")||is("version"))
- { checkeol;
- v_info(0);
- return; }
- case 'V': if(is("V"))
- { checkeol;
- v_info(1);
- return; }
- default: printf("\7unknown command \"%c%s\"\n",c,dicp);
- printf("type /h for help\n");
- while((ch=getchar())!='\n'&&ch!=EOF);
- return;
- } /* end of switch statement */
- xschars();
-}
-
-manaction()
-{ sprintf(linebuf,"\"%s/menudriver\" \"%s/manual\"",miralib,miralib);
- system(linebuf);
-} /* put quotes around both pathnames to allow for spaces in miralib 8.5.06 */
-
-editfile(t,line)
-char *t;
-word line;
-{ char *ebuf=linebuf;
- char *p=ebuf,*q=editor;
- word tdone=0;
- if(line==0)line=1; /* avoids warnings in some versions of vi */
- while(*p++ = *q++)
- if(p[-1]=='\\'&&(q[0]=='!'||q[0]=='%'))p[-1]= *q++; else
- if(p[-1]=='!')
- (void)
- sprintf(p-1,"%d",line),
- p+=strlen(p); else
- if(p[-1]=='%')p[-1]='"',*p='\0', /* quote filename 9.5.06 */
- (void)strncat(p,t,BUFSIZE+ebuf-p),
- p+=strlen(p),
- *p++ = '"',*p='\0',
- tdone=1;
- if(!tdone)
- p[-1] = ' ',
- *p++ = '"',*p='\0', /* quote filename 9.5.06 */
- (void)strncat(p,t,BUFSIZE+ebuf-p),
- p+=strlen(p),
- *p++ = '"',*p='\0';
- /* printf("%s\n",ebuf); /* DEBUG */
- system(ebuf);
- if(src_update())loadfile(current_script);
- return;
-}
-
-xschars()
-{ word ch;
- printf("\7extra characters at end of command\n");
- while((ch=getchar())!='\n'&&ch!=EOF);
-}
-
-reverse(x) /* x is a cons list */
-word x;
-{ word y = NIL;
- while(x!=NIL)y = cons(hd[x],y), x = tl[x];
- return(y);
-}
-
-shunt(x,y) /* equivalent to append(reverse(x),y) */
-word x,y;
-{ while(x!=NIL)y = cons(hd[x],y), x = tl[x];
- return(y);
-}
-
-char *presym[] =
- {"abstype","div","if","mod","otherwise","readvals","show","type","where",
- "with", 0};
-word presym_n[] =
- { 21, 8, 15, 8, 15, 31, 23, 22, 15,
- 21 };
-
-#include <ctype.h>
-
-filequote(p) /* write p to stdout with <quotes> if appropriate */
-char *p; /* p is a pathname */
-{ static mlen=0;
- if(!mlen)mlen=(rindex(PRELUDE,'/')-PRELUDE)+1;
- if(strncmp(p,PRELUDE,mlen)==0)
- printf("<%s>",p+mlen);
- else printf("\"%s\"",p);
-} /* PRELUDE is a convenient string with the miralib prefix */
-
-finger(n) /* find info about name stored at dicp */
-char *n;
-{ word x,line;
- char *s;
- x=findid(n);
- if(x!=NIL&&id_type(x)!=undef_t)
- { if(id_who(x)!=NIL)
- s=(char *)hd[line=get_here(x)],line=tl[line];
- if(!lastid)lastid=x;
- report_type(x);
- if(id_who(x)==NIL)printf(" ||primitive to Miranda\n");
- else { char *aka=getaka(x);
- if(aka==get_id(x))aka=NULL; /* don't report alias to self */
- if(id_val(x)==UNDEF&&id_type(x)!=wrong_t)
- printf(" ||(UNDEFINED) specified in "); else
- if(id_val(x)==FREE)
- printf(" ||(FREE) specified in "); else
- if(id_type(x)==type_t&&t_class(x)==free_t)
- printf(" ||(free type) specified in "); else
- printf(" ||%sdefined in ",
- id_type(x)==type_t
- && t_class(x)==abstract_t?"(abstract type) ":
- id_type(x)==type_t
- && t_class(x)==algebraic_t?"(algebraic type) ":
- id_type(x)==type_t
- && t_class(x)==placeholder_t?"(placeholder type) ":
- id_type(x)==type_t
- && t_class(x)==synonym_t?"(synonym type) ":
- "");
- filequote(s);
- if(baded||rechecking)printf(" line %d",line);
- if(aka)printf(" (as \"%s\")\n",aka);
- else putchar('\n');
- }
- if(atobject)printf("%s = ",get_id(x)),
- out(stdout,id_val(x)),putchar('\n');
- return; }
- diagnose(n);
-}
-
-diagnose(n)
-char *n;
-{ word i=0;
- if(isalpha(n[0]))
- while(n[i]&&okid(n[i]))i++;
- if(n[i]){ printf("\"%s\" -- not an identifier\n",n); return; }
- for(i=0;presym[i];i++)
- if(strcmp(n,presym[i])==0)
- { printf("%s -- keyword (see manual, section %d)\n",n,presym_n[i]);
- return; }
- printf("identifier \"%s\" not in scope\n",n);
-}
-
-static word sorted=0; /* flag to avoid repeatedly sorting fil_defs */
-static word leftist; /* flag to alternate bias of padding in justification */
-word words[colmax]; /* max plausible size of screen */
-
-allnamescom()
-{ word s;
- word x=ND;
- word y=x,z=0;
- leftist=0;
- namescom(make_fil(nostdenv?0:STDENV,0,0,primenv));
- if(files==NIL)return; else s=tl[files];
- while(s!=NIL)namescom(hd[s]),s=tl[s];
- namescom(hd[files]);
- sorted=1;
- /* now print warnings, if any */
- /*if(ND!=NIL&&id_type(hd[ND])==type_t)
- { printf("ILLEGAL EXPORT LIST - MISSING TYPENAME%s: ",tl[ND]==NIL?"":"S");
- printlist("",ND);
- return; } /* install if incomplete export list is escalated to error */
- while(x!=NIL&&id_type(hd[x])==undef_t)x=tl[x];
- while(y!=NIL&&id_type(hd[y])!=undef_t)y=tl[y];
- if(x!=NIL)
- { printf("WARNING, SCRIPT CONTAINS TYPE ERRORS: ");
- for(;x!=NIL;x=tl[x])
- if(id_type(hd[x])!=undef_t)
- { if(!z)z=1; else putchar(',');
- out(stdout,hd[x]); }
- printf(";\n"); }
- if(y!=NIL)
- { printf("%s UNDEFINED NAMES: ",z?"AND":"WARNING, SCRIPT CONTAINS");
- z=0;
- for(;y!=NIL;y=tl[y])
- if(id_type(hd[y])==undef_t)
- { if(!z)z=1; else putchar(',');
- out(stdout,hd[y]); }
- printf(";\n"); }
-}
-/* There are two kinds of entry in ND
- undefined names: val=UNDEF, type=undef_t
- type errors: val=UNDEF, type=wrong_t
-*/
-
-#define tolerance 3
- /* max number of extra spaces we are willing to insert */
-
-namescom(l) /* l is an element of `files' */
-word l;
-{ word n=fil_defs(l),col=0,undefs=NIL,wp=0;
- word scrwd = twidth();
- if(!sorted&&n!=primenv) /* primenv already sorted */
- fil_defs(l)=n=alfasort(n); /* also removes pnames */
- if(n==NIL)return; /* skip empty files */
- if(get_fil(l))filequote(get_fil(l));
- else printf("primitive:");
- printf("\n");
- while(n!=NIL)
- { if(id_type(hd[n])==wrong_t||id_val(hd[n])!=UNDEF)
- { word w=strlen(get_id(hd[n]));
- if(col+w<scrwd)col += (col!=0); else
- if(wp&&col+w>=scrwd)
- { word i,r,j;
- if(wp>1)i=(scrwd-col)/(wp-1),r=(scrwd-col)%(wp-1);
- if(i+(r>0)>tolerance)i=r=0;
- if(leftist)
- for(col=0;col<wp;)
- { printf("%s",get_id(words[col]));
- if(++col<wp)
- spaces(1+i+(r-- >0)); }
- else
- for(r=wp-1-r,col=0;col<wp;)
- { printf("%s",get_id(words[col]));
- if(++col<wp)
- spaces(1+i+(r-- <=0)); }
- leftist=!leftist,wp=0,col=0,putchar('\n'); }
- col+=w;
- words[wp++]=hd[n]; }
- else undefs=cons(hd[n],undefs); /* undefined but have good types */
- n = tl[n]; }
- if(wp)
- for(col=0;col<wp;)
- printf("%s",get_id(words[col])),putc(++col==wp?'\n':' ',stdout);
- if(undefs==NIL)return;
- undefs=reverse(undefs);
- printlist("SPECIFIED BUT NOT DEFINED: ",undefs);
-}
-
-word detrop=NIL; /* list of unused local definitions */
-word rfl=NIL; /* list of include components containing type orphans */
-word bereaved; /* typenames referred to in exports and not exported */
-word ld_stuff=NIL;
- /* list of list of files, to be unloaded if mkincludes interrupted */
-
-loadfile(t)
-char *t;
-{ extern word fileq;
- extern word current_id,includees,embargoes,exportfiles,freeids,exports;
- extern word fnts,FBS,disgusting,nextpn;
- word h=NIL; /* location of %export directive, if present */
- loading=1;
- errs=errline=0;
- current_script=t;
- oldfiles=NIL;
- unload();
- if(stat(t,&buf))
- { if(initialising){ fprintf(stderr,"panic: %s not found\n",t); exit(1); }
- if(verbosity)printf("new file %s\n",t);
- if(magic)fprintf(stderr,"mira -exec %s%s\n",t,": no such file"),exit(1);
- if(making&&ideep==0)printf("mira -make %s%s\n",t,": no such file");
- else oldfiles=cons(make_fil(t,0,0,NIL),NIL);
- /* for correct record of sources */
- loading=0;
- return; }
- if(!openfile(t))
- { if(initialising){ fprintf(stderr,"panic: cannot open %s\n",t); exit(1); }
- printf("cannot open %s\n",t);
- oldfiles=cons(make_fil(t,0,0,NIL),NIL);
- loading=0;
- return; }
- files = cons(make_fil(t,fm_time(t),1,NIL),NIL);
- current_file = hd[files],tl[hd[fileq]] = current_file;
- if(initialising&&strcmp(t,PRELUDE)==0)privlib(); else
- if(initialising||nostdenv==1)
- if(strcmp(t,STDENV)==0)stdlib();
- c = ' ';
- col = 0;
- s_in = (FILE *)hd[hd[fileq]];
- adjust_prefix(t);
-/*if(magic&&!initialising)
- { if(!(getc(s_in)=='#'&&getc(s_in)=='!'))
- { files=NIL; return; }
- while(getc(s_in)!='\n');
- commandmode=1;
- c=MAGIC; }
- else /* change to magic scripts 19.11.2013 */
- commandmode = 0;
- if(verbosity||making)printf("compiling %s\n",t);
- nextpn=0; /* lose pnames */
- embargoes=detrop=
- fnts=rfl=bereaved=ld_stuff=exportfiles=freeids=exports=includees=FBS=NIL;
- yyparse();
- if(!SYNERR&&exportfiles!=NIL)
- { /* check pathnames in exportfiles have unique bindings */
- word s,i,count;
- for(s=exportfiles;s!=NIL;s=tl[s])
- if(hd[s]==PLUS) /* add current script (less freeids) to exports */
- { for(i=fil_defs(hd[files]);i!=NIL;i=tl[i])
- if(isvariable(hd[i])&&!isfreeid(hd[i]))
- tl[exports]=add1(hd[i],tl[exports]);
- } else
- /* pathnames are expanded to their contents in mkincludes */
- { for(count=0,i=includees;i!=NIL;i=tl[i])
- if(!strcmp((char *)hd[hd[hd[i]]],(char *)hd[s]))
- hd[s]=hd[hd[hd[i]]]/*sharing*/,count++;
- if(count!=1)
- SYNERR=1,
- printf("illegal fileid \"%s\" in export list (%s)\n",
- (char *)hd[s],
- count?"ambiguous":"not %included in script");
- }
- if(SYNERR)
- sayhere(hd[exports],1),
- printf("compilation abandoned\n");
- }
- if(!SYNERR&&includees!=NIL)
- files=append1(files,mkincludes(includees)),includees=NIL;
- ld_stuff=NIL;
- if(!SYNERR&!disgusting)
- { if(verbosity||making&&!mkexports&&!mksources)
- printf("checking types in %s\n",t);
- checktypes();
- /* printf("typecheck complete\n"); /* DEBUG */ }
- if(!SYNERR&&exports!=NIL)
- if(ND!=NIL)exports=NIL; else /* skip check, cannot be %included */
- { /* check exports all present and close under type info */
- word e,u=NIL,n=NIL,c=NIL;
- h=hd[exports]; exports=tl[exports];
- for(e=embargoes;e!=NIL;e=tl[e])
- { if(id_type(hd[e])==undef_t)u=cons(hd[e],u),ND=add1(hd[e],ND); else
- if(!member(exports,hd[e]))n=cons(hd[e],n); }
- if(embargoes!=NIL)
- exports=setdiff(exports,embargoes);
- exports=alfasort(exports);
- for(e=exports;e!=NIL;e=tl[e])
- if(id_type(hd[e])==undef_t)u=cons(hd[e],u),ND=add1(hd[e],ND); else
- if(id_type(hd[e])==type_t&&t_class(hd[e])==algebraic_t)
- c=shunt(t_info(hd[e]),c); /* constructors */
- if(exports==NIL)printf("warning, export list has void contents\n");
- else exports=append1(alfasort(c),exports);
- if(n!=NIL)
- { printf("redundant entr%s in export list:",tl[n]==NIL?"y":"ies");
- while(n!=NIL)printf(" -%s",get_id(hd[n])),n=tl[n]; n=1; /* flag */
- putchar('\n'); }
- if(u!=NIL)exports=NIL,
- printlist("undefined names in export list: ",u);
- if(u!=NIL)sayhere(h,1),h=NIL; else
- if(exports==NIL||n!=NIL)out_here(stderr,h,1),h=NIL;
- /* for warnings call out_here not sayhere, so errinfo not saved in dump */
- }
- if(!SYNERR&&ND==NIL&&(exports!=NIL||tl[files]!=NIL))
- { /* find out if script can create type orphans when %included */
- word e1,t;
- word r=NIL; /* collect list of referenced typenames */
- word e=NIL; /* and list of exported typenames */
- if(exports!=NIL)
- for(e1=exports;e1!=NIL;e1=tl[e1])
- { if((t=id_type(hd[e1]))==type_t)
- if(t_class(hd[e1])==synonym_t)
- r=UNION(r,deps(t_info(hd[e1])));
- else e=cons(hd[e1],e);
- else r=UNION(r,deps(t)); } else
- for(e1=fil_defs(hd[files]);e1!=NIL;e1=tl[e1])
- { if((t=id_type(hd[e1]))==type_t)
- if(t_class(hd[e1])==synonym_t)
- r=UNION(r,deps(t_info(hd[e1])));
- else e=cons(hd[e1],e);
- else r=UNION(r,deps(t)); }
- for(e1=freeids;e1!=NIL;e1=tl[e1])
- if((t=id_type(hd[hd[e1]]))==type_t)
- if(t_class(hd[hd[e1]])==synonym_t)
- r=UNION(r,deps(t_info(hd[hd[e1]])));
- else e=cons(hd[hd[e1]],e);
- else r=UNION(r,deps(t));
- /*printlist("r: ",r); /* DEBUG */
- for(;r!=NIL;r=tl[r])
- if(!member(e,hd[r]))bereaved=cons(hd[r],bereaved);
- /*printlist("bereaved: ",bereaved); /* DEBUG */
- }
- if(exports!=NIL&&bereaved!=NIL)
- { extern word newtyps;
- word b=intersection(bereaved,newtyps);
- /*printlist("newtyps",newtyps); /* DEBUG */
- if(b!=NIL)
- /*ND=b; /* to escalate to type error, see also allnamescom */
- printf("warning, export list is incomplete - missing typename%s: ",
- tl[b]==NIL?"":"s"),
- printlist("",b);
- if(b!=NIL&&h!=NIL)out_here(stdout,h,1); /* sayhere(h,1) for error */
- }
- if(!SYNERR&&detrop!=NIL)
- { word gd=detrop;
- while(detrop!=NIL&&tag[dval(hd[detrop])]==LABEL)detrop=tl[detrop];
- if(detrop!=NIL)
- printf("warning, script contains unused local definitions:-\n");
- while(detrop!=NIL)
- { out_here(stdout,hd[hd[tl[dval(hd[detrop])]]],0), putchar('\t');
- out_pattern(stdout,dlhs(hd[detrop])), putchar('\n');
- detrop=tl[detrop];
- while(detrop!=NIL&&tag[dval(hd[detrop])]==LABEL)
- detrop=tl[detrop]; }
- while(gd!=NIL&&tag[dval(hd[gd])]!=LABEL)gd=tl[gd];
- if(gd!=NIL)
- printf("warning, grammar contains unused nonterminals:-\n");
- while(gd!=NIL)
- { out_here(stdout,hd[dval(hd[gd])],0), putchar('\t');
- out_pattern(stdout,dlhs(hd[gd])), putchar('\n');
- gd=tl[gd];
- while(gd!=NIL&&tag[dval(hd[gd])]!=LABEL)gd=tl[gd]; }
- /* note, usual rhs is tries(pat,list(label(here,exp)))
- grammar rhs is label(here,...) */
- }
- if(!SYNERR)
- { word x; extern word lfrule,polyshowerror;
- /* we invoke the code generator */
- lfrule=0;
- for(x=fil_defs(hd[files]);x!=NIL;x=tl[x])
- if(id_type(hd[x])!=type_t)
- { current_id=hd[x];
- polyshowerror=0;
- id_val(hd[x])=codegen(id_val(hd[x]));
- if(polyshowerror)id_val(hd[x])=UNDEF;
- /* nb - one remaining class of typerrs trapped in codegen,
- namely polymorphic show or readvals */
- }
- current_id=0;
- if(lfrule&&(verbosity||making))
- printf("grammar optimisation: %d common left factors found\n",lfrule);
- if(initialising&&ND!=NIL)
- { fprintf(stderr,"panic: %s contains errors\n",okprel?"stdenv":"prelude");
- exit(1); }
- if(initialising)makedump(); else
- if(normal(t)) /* file ends ".m", formerly if(!magic) */
- fixexports(),makedump(),unfixexports();
- /* changed 26.11.2019 to allow dump of magic scripts ending ".m" */
- if(!errline&&errs&&(char *)hd[errs]==current_script)
- errline=tl[errs]; /* soft error (posn not saved in dump) */
- ND=alfasort(ND);
- /* we could sort and remove pnames from each defs component immediately
- after makedump(), instead of doing this in namescom */
- loading=0;
- return; }
- /* otherwise syntax error found */
- if(initialising)
- { fprintf(stderr,"panic: cannot compile %s\n",okprel?"stdenv":"prelude"); exit(1); }
- oldfiles=files;
- unload();
- if(normal(t)&&SYNERR!=2)makedump(); /* make syntax error dump */
- /* allow dump of magic script in ".m", was if(!magic&&) 26.11.2019 */
- SYNERR=0;
- loading=0;
-}
-
-isfreeid(x)
-{ return(id_type(x)==type_t?t_class(x)==free_t:id_val(x)==FREE); }
-
-word internals=NIL; /* used by fix/unfixexports, list of names not exported */
-#define paint(x) id_val(x)=ap(EXPORT,id_val(x))
-#define unpainted(x) (tag[id_val(x)]!=AP||hd[id_val(x)]!=EXPORT)
-#define unpaint(x) id_val(x)=tl[id_val(x)]
-
-fixexports()
-{ extern exports,exportfiles,embargoes,freeids;
- word e=exports,f;
- /* printlist("exports: ",e); /* DEBUG */
- for(;e!=NIL;e=tl[e])paint(hd[e]);
- internals=NIL;
- if(exports==NIL&&exportfiles==NIL&&embargoes==NIL) /*no %export in script*/
- { for(e=freeids;e!=NIL;e=tl[e])
- internals=cons(privatise(hd[hd[e]]),internals);
- for(f=tl[files];f!=NIL;f=tl[f])
- for(e=fil_defs(hd[f]);e!=NIL;e=tl[e])
- { if(tag[hd[e]]==ID)
- internals=cons(privatise(hd[e]),internals); }}
- else for(f=files;f!=NIL;f=tl[f])
- for(e=fil_defs(hd[f]);e!=NIL;e=tl[e])
- { if(tag[hd[e]]==ID&&unpainted(hd[e]))
- internals=cons(privatise(hd[e]),internals); }
- /* optimisation, need not do this to `silent' components - fix later */
- /*printlist("internals: ",internals); /* DEBUG */
- for(e=exports;e!=NIL;e=tl[e])unpaint(hd[e]);
-} /* may not be interrupt safe, re unload() */
-
-unfixexports()
-{ /*printlist("internals: ",internals); /* DEBUG */
- word i=internals;
- if(mkexports)return; /* in this case don't want internals restored */
- while(i!=NIL) /* lose */
- publicise(hd[i]),i=tl[i];
- internals=NIL;
-} /* may not be interrupt safe, re unload() */
-
-privatise(x) /* change id to pname, and return new id holding it as value */
-word x;
-{ extern word namebucket[],*pnvec;
- word n = make_pn(x),h=namebucket[hash(get_id(x))],i;
- if(id_type(x)==type_t)
- t_info(x)=cons(datapair(getaka(x),0),get_here(x));
- /* to assist identification of danging type refs - see typesharing code
- in mkincludes */
- /* assumption - nothing looks at the t_info after compilation */
- if(id_val(x)==UNDEF) /* name specified but not defined */
- id_val(x)= ap(datapair(getaka(x),0),get_here(x));
- /* this will generate sensible error message on attempt to use value
- see reduction rule for DATAPAIR */
- pnvec[i=hd[n]]=x;
- tag[n]=ID;hd[n]=hd[x];
- tag[x]=STRCONS;hd[x]=i;
- while(hd[h]!=x)h=tl[h];
- hd[h]=n;
- return(n);
-} /* WARNING - dependent on internal representation of ids and pnames */
-/* nasty problem - privatisation can screw AKA's */
-
-publicise(x) /* converse of the above, applied to the new id */
-word x;
-{ extern word namebucket[];
- word i=id_val(x),h=namebucket[hash(get_id(x))];
- tag[i]=ID,hd[i]=hd[x];
- /* WARNING - USES FACT THAT tl HOLDS VALUE FOR BOTH ID AND PNAME */
- if(tag[tl[i]]==AP&&tag[hd[tl[i]]]==DATAPAIR)
- tl[i]=UNDEF; /* undo kludge, see above */
- while(hd[h]!=x)h=tl[h];
- hd[h]=i;
- return(i);
-}
-
-static sigflag=0;
-
-sigdefer()
-{ /* printf("sigdefer()\n"); /* DEBUG */
- sigflag=1; } /* delayed signal handler, installed during load_script() */
-
-mkincludes(includees)
-word includees;
-{ extern word FBS,BAD_DUMP,CLASHES,exportfiles,exports,TORPHANS;
- word pid,result=NIL,tclashes=NIL;
- includees=reverse(includees); /* process in order of occurrence in script */
- if(pid=fork())
- { /* parent */
- word status;
- if(pid==-1)
- { perror("UNIX error - cannot create process"); /* will say why */
- if(ideep>6) /* perhaps cyclic %include */
- fprintf(stderr,"error occurs %d deep in %%include files\n",ideep);
- if(ideep)exit(2);
- SYNERR=2; /* special code to prevent makedump() */
- printf("compilation of \"%s\" abandoned\n",current_script);
- return(NIL); }
- while(pid!=wait(&status));
- if((WEXITSTATUS(status))==2) /* child aborted */
- if(ideep)exit(2); /* recursive abortion of parent process */
- else { SYNERR=2;
- printf("compilation of \"%s\" abandoned\n",current_script);
- return(NIL); }
- /* if we get to here child completed normally, so carry on */
- }
- else { /* child does equivalent of `mira -make' on each includee */
- extern word oldfiles;
- (void)signal(SIGINT,SIG_DFL); /* don't trap interrupts */
- ideep++; making=1; make_status=0; echoing=listing=verbosity=magic=0;
- setjmp(env); /* will return here on blankerr (via reset) */
- while(includees!=NIL&&!make_status) /* stop at first bad includee */
- { undump((char *)hd[hd[hd[includees]]]);
- if(ND!=NIL||files==NIL&&oldfiles!=NIL)make_status=1;
- /* any errors in dump? */
- includees=tl[includees];
- } /* obscure bug - undump above can reinvoke compiler, which
- side effects compiler variable `includees' - to fix this
- had to make sure child is holding local copy of includees*/
- exit(make_status); }
- sigflag=0;
- for(;includees!=NIL;includees=tl[includees])
- { word x=NIL;
- sighandler oldsig;
- FILE *f;
- char *fn=(char *)hd[hd[hd[includees]]];
- extern word DETROP,MISSING,ALIASES,TSUPPRESSED,*stackp,*dstack;
- (void)strcpy(dicp,fn);
- (void)strcpy(dicp+strlen(dicp)-1,obsuffix);
- if(!making) /* cannot interrupt load_script() */
- oldsig=signal(SIGINT,(sighandler)sigdefer);
- if(f=fopen(dicp,"r"))
- x=load_script(f,fn,hd[tl[hd[includees]]],tl[tl[hd[includees]]],0),
- fclose(f);
- ld_stuff=cons(x,ld_stuff);
- if(!making)(void)signal(SIGINT,oldsig);
- if(sigflag)sigflag=0,(* oldsig)(); /* take deferred interrupt */
- if(f&&!BAD_DUMP&&x!=NIL&&ND==NIL&&CLASHES==NIL&&ALIASES==NIL&&
- TSUPPRESSED==NIL&&DETROP==NIL&&MISSING==NIL)
- /* i.e. if load_script worked ok */
- { /* stuff here is to share repeated file components
- issues:
- Consider only includees (fil_share=1), not insertees.
- Effect of sharing is to replace value fields in later copies
- by (pointers to) corresponding ids in first copy - so sharing
- transmitted thru dumps. It is illegal to have more than one
- copy of a (non-synonym) type in the same scope, even under
- different names. */
- word y,z;
- /* printf("start share analysis\n"); /* DEBUG */
- if(TORPHANS)rfl=shunt(x,rfl); /* file has type orphans */
- for(y=x;y!=NIL;y=tl[y])fil_inodev(hd[y])=inodev(get_fil(hd[y]));
- for(y=x;y!=NIL;y=tl[y])
- if(fil_share(hd[y]))
- for(z=result;z!=NIL;z=tl[z])
- if(fil_share(hd[z])&&same_file(hd[y],hd[z])
- &&fil_time(hd[y])==fil_time(hd[z]))
- { word p=fil_defs(hd[y]),q=fil_defs(hd[z]);
- for(;p!=NIL&&q!=NIL;p=tl[p],q=tl[q])
- if(tag[hd[p]]==ID)
- if(id_type(hd[p])==type_t&&
- (tag[hd[q]]==ID||tag[pn_val(hd[q])]==ID))
- { /* typeclash - record in tclashes */
- word w=tclashes;
- word orig=tag[hd[q]]==ID?hd[q]:pn_val(hd[q]);
- if(t_class(hd[p])==synonym_t)continue;
- while(w!=NIL&&((char *)hd[hd[w]]!=get_fil(hd[z])
- ||hd[tl[hd[w]]]!=orig))
- w=tl[w];
- if(w==NIL)
- w=tclashes=cons(strcons(get_fil(hd[z]),
- cons(orig,NIL)),tclashes);
- tl[tl[hd[w]]]=cons(hd[p],tl[tl[hd[w]]]);
- }
- else the_val(hd[q])=hd[p];
- else the_val(hd[p])=hd[q];
- /*following test redundant - remove when sure is ok*/
- if(p!=NIL||q!=NIL)
- fprintf(stderr,"impossible event in mkincludes\n");
- /*break; /* z loop -- NO! (see liftbug) */
- }
- if(member(exportfiles,(word)fn))
- { /* move ids of x onto exports */
- for(y=x;y!=NIL;y=tl[y])
- for(z=fil_defs(hd[y]);z!=NIL;z=tl[z])
- if(isvariable(hd[z]))
- tl[exports]=add1(hd[z],tl[exports]);
- /* skip pnames, constructors (expanded later) */
- }
- result=append1(result,x);
- /* keep `result' in front-first order */
- if(hd[FBS]==NIL)FBS=tl[FBS];
- else hd[FBS]=cons(tl[hd[hd[includees]]],hd[FBS]); /* hereinfo */
- /* printf("share analysis finished\n"); /* DEBUG */
- continue; }
- /* something wrong - find out what */
- if(!f)result=cons(make_fil(hd[hd[hd[includees]]],
- fm_time(fn),0,NIL),result); else
- if(x==NIL&&BAD_DUMP!= -2)result=append1(result,oldfiles),oldfiles=NIL;
- else result=append1(result,x);
- /* above for benefit of `oldfiles' */
- /* BAD_DUMP -2 is nameclashes due to aliasing */
- SYNERR=1;
- printf("unsuccessful %%include directive ");
- sayhere(tl[hd[hd[includees]]],1);
-/* if(!f)printf("\"%s\" non-existent or unreadable\n",fn), */
- if(!f)printf("\"%s\" cannot be loaded\n",fn),
- CLASHES=DETROP=MISSING=NIL;
- /* just in case not cleared from a previous load_script() */
- else
- if(BAD_DUMP== -2)
- printlist("aliasing causes nameclashes: ",CLASHES),
- CLASHES=NIL; else
- if(ALIASES!=NIL||TSUPPRESSED!=NIL)
- { if(ALIASES!=NIL)
- printf("alias fails (name%s not found in file",
- tl[ALIASES]==NIL?"":"s"),
- printlist("): ",ALIASES),ALIASES=NIL;
- if(TSUPPRESSED!=NIL)
- { printf("illegal alias (cannot suppress typename%s):",
- tl[TSUPPRESSED]==NIL?"":"s");
- while(TSUPPRESSED!=NIL)
- printf(" -%s",get_id(hd[TSUPPRESSED])),
- TSUPPRESSED=tl[TSUPPRESSED];
- putchar('\n'); }
- /* if -typename allowed, remember to look for type orphans */
- }else
- if(BAD_DUMP)printf("\"%s\" has bad data in dump file\n",fn); else
- if(x==NIL)printf("\"%s\" contains syntax error\n",fn); else
- if(ND!=NIL)
- printf("\"%s\" contains undefined names or type errors\n",fn);
- if(ND==NIL&&CLASHES!=NIL) /* can have this and failed aliasing */
- printf("\"%s\" ",fn),printlist("causes nameclashes: ",CLASHES);
- while(DETROP!=NIL&&tag[hd[DETROP]]==CONS)
- { word fa=hd[tl[hd[DETROP]]],ta=tl[tl[hd[DETROP]]];
- char *pn=get_id(hd[hd[DETROP]]);
- if(fa== -1||ta== -1)
- printf("`%s' has binding of wrong kind ",pn),
- printf(fa== -1?"(should be \"= value\" not \"== type\")\n"
- :"(should be \"== type\" not \"= value\")\n");
- else
- printf("`%s' has == binding of wrong arity ",pn),
- printf("(formal has arity %d, actual has arity %d)\n",fa,ta);
- DETROP=tl[DETROP]; }
- if(DETROP!=NIL)
- printf("illegal parameter binding (name%s not %%free in file",
- tl[DETROP]==NIL?"":"s"),
- printlist("): ",DETROP),DETROP=NIL;
- if(MISSING!=NIL)
- printf("missing parameter binding%s: ",tl[MISSING]==NIL?"":"s");
- while(MISSING!=NIL)
- printf("%s%s",(char *)hd[hd[MISSING]],tl[MISSING]==NIL?";\n":","),
- MISSING=tl[MISSING];
- printf("compilation abandoned\n");
- stackp=dstack; /* in case of BAD_DUMP */
- return(result); } /* for unload() */
- if(tclashes!=NIL)
- { printf("TYPECLASH - the following type%s multiply named:\n",
- tl[tclashes]==NIL?" is":"s are");
- /* structure of tclashes is list of strcons(filname,list-of-ids) */
- for(;tclashes!=NIL;tclashes=tl[tclashes])
- { printf("\'%s\' of file \"%s\", as: ",
- getaka(hd[tl[hd[tclashes]]]),
- (char *)hd[hd[tclashes]]);
- printlist("",alfasort(tl[hd[tclashes]])); }
- printf("typecheck cannot proceed - compilation abandoned\n");
- SYNERR=1;
- return(result); } /* for unload */
- return(result);
-}
-
-word tlost=NIL;
-word pfrts=NIL; /* list of private free types bound in this script */
-
-readoption() /* readopt type orphans */
-{ word f,t;
- extern word TYPERRS,FBS;
- pfrts=tlost=NIL;
- /* exclude anonymous free types, these dealt with later by mcheckfbs() */
- if(FBS!=NIL)
- for(f=FBS;f!=NIL;f=tl[f])
- for(t=tl[hd[f]];t!=NIL;t=tl[t])
- if(tag[hd[hd[t]]]==STRCONS&&tl[tl[hd[t]]]==type_t)
- pfrts=cons(hd[hd[t]],pfrts);
- /* this may needlessly scan `silent' files - fix later */
- for(;rfl!=NIL;rfl=tl[rfl])
- for(f=fil_defs(hd[rfl]);f!=NIL;f=tl[f])
- if(tag[hd[f]]==ID)
- if((t=id_type(hd[f]))==type_t)
- { if(t_class(hd[f])==synonym_t)
- t_info(hd[f])=fixtype(t_info(hd[f]),hd[f]); }
- else id_type(hd[f])=fixtype(t,hd[f]);
- if(tlost==NIL)return;
- TYPERRS++;
- printf("MISSING TYPENAME%s\n",tl[tlost]==NIL?"":"S");
- printf("the following type%s no name in this scope:\n",
- tl[tlost]==NIL?" is needed but has":"s are needed but have");
- /* structure of tlost is list of cons(losttype,list-of-ids) */
- for(;tlost!=NIL;tlost=tl[tlost])
- { /* printf("tinfo_tlost=");out(stdout,t_info(hd[hd[tlost]]));
- putchar(';'); /*DEBUG */
- printf("\'%s\' of file \"%s\", needed by: ",
- (char *)hd[hd[t_info(hd[hd[tlost]])]],
- (char *)hd[tl[t_info(hd[hd[tlost]])]]);
- printlist("",alfasort(tl[hd[tlost]])); }
-}
-
-/*fixtype(t,x)
-int t,x;
-{ int t1;
- t1=fixtype1(t,x);
- printf("fixing type of %s\n",get_id(x));
- out_type(t); printf(" := ");
- out_type(t1); putchar('\n');
- return(t1);
-} /* DEBUG */
-
-fixtype(t,x) /* substitute out any indirected typenames in t */
-word t,x;
-{ switch(tag[t])
- { case AP:
- case CONS: tl[t]=fixtype(tl[t],x);
- hd[t]=fixtype(hd[t],x);
- default: return(t);
- case STRCONS: if(member(pfrts,t))return(t); /* see jrcfree.bug */
- while(tag[pn_val(t)]!=CONS)t=pn_val(t);/*at most twice*/
- if(tag[t]!=ID)
- { /* lost type - record in tlost */
- word w=tlost;
- while(w!=NIL&&hd[hd[w]]!=t)w=tl[w];
- if(w==NIL)
- w=tlost=cons(cons(t,cons(x,NIL)),tlost);
- tl[hd[w]]=add1(x,tl[hd[w]]);
- }
- return(t);
- }
-}
-
-#define mask(c) (c&0xDF)
-/* masks out lower case bit, which is 0x20 */
-alfa_ls(a,b) /* 'DICTIONARY ORDER' - not currently used */
-char *a,*b;
-{ while(*a&&mask(*a)==mask(*b))a++,b++;
- if(mask(*a)==mask(*b))return(strcmp(a,b)<0); /* lower case before upper */
- return(mask(*a)<mask(*b));
-}
-
-alfasort(x) /* also removes non_IDs from result */
-word x;
-{ word a=NIL,b=NIL,hold=NIL;
- if(x==NIL)return(NIL);
- if(tl[x]==NIL)return(tag[hd[x]]!=ID?NIL:x);
- while(x!=NIL) /* split x */
- { if(tag[hd[x]]==ID)hold=a,a=cons(hd[x],b),b=hold;
- x=tl[x]; }
- a=alfasort(a),b=alfasort(b);
- /* now merge two halves back together */
- while(a!=NIL&&b!=NIL)
- if(strcmp(get_id(hd[a]),get_id(hd[b]))<0)x=cons(hd[a],x),a=tl[a];
- else x=cons(hd[b],x),b=tl[b];
- if(a==NIL)a=b;
- while(a!=NIL)x=cons(hd[a],x),a=tl[a];
- return(reverse(x));
-}
-
-unsetids(d) /* d is a list of identifiers */
-word d;
-{ while(d!=NIL)
- { if(tag[hd[d]]==ID)id_val(hd[d])=UNDEF,
- id_who(hd[d])=NIL,
- id_type(hd[d])=undef_t;
- d=tl[d]; } /* should we remove from namebucket ? */
-}
-
-unload() /* clear out current script in preparation for reloading */
-{ extern word TABSTRS,SGC,speclocs,newtyps,rv_script,algshfns,nextpn,nolib,
- includees,freeids;
- word x;
- sorted=0;
- speclocs=NIL;
- nextpn=0; /* lose pnames */
- rv_script=0;
- algshfns=NIL;
- unsetids(newtyps);
- newtyps=NIL;
- unsetids(freeids);
- freeids=includees=SGC=freeids=TABSTRS=ND=NIL;
- unsetids(internals);
- internals=NIL;
- while(files!=NIL)
- { unsetids(fil_defs(hd[files]));
- fil_defs(hd[files])=NIL;
- files = tl[files]; }
- for(;ld_stuff!=NIL;ld_stuff=tl[ld_stuff])
- for(x=hd[ld_stuff];x!=NIL;x=tl[x])unsetids(fil_defs(hd[x]));
-}
-
-yyerror(s) /* called by YACC in the event of a syntax error */
-char *s;
-{ extern word yychar;
- if(SYNERR)return; /* error already reported, so shut up */
- if(echoing)printf("\n");
- printf("%s - unexpected ",s);
- if(yychar==OFFSIDE&&(c==EOF||c=='|'))
- { if(c==EOF) /* special case introduced by fix for dtbug */
- printf("end of file"); else
- printf("token '|'");
- /* special case introduced by sreds fix to offside rule */
- } else
- { printf(yychar==0?commandmode?"newline":"end of file":"token ");
- if(yychar>=256)putchar('\"');
- if(yychar!=0)out2(stdout,yychar);
- if(yychar>=256)putchar('\"'); }
- printf("\n");
- SYNERR=1;
- reset_lex();
-}
-
-syntax(s) /* called by actions after discovering a (context sensitive) syntax
- error */
-char *s;
-{ if(SYNERR)return;
- if(echoing)printf("\n");
- printf("syntax error: %s",s);
- SYNERR=1; /* this will stop YACC at its next call to yylex() */
- reset_lex();
-}
-
-acterror() /* likewise, but assumes error message output by caller */
-{ if(SYNERR)return;
- SYNERR=1; /* to stop YACC at next symbol */
- reset_lex();
-}
-
-mira_setup()
-{ extern word common_stdin,common_stdinb,cook_stdin;
- setupheap();
- tsetup();
- reset_pns();
- bigsetup();
- common_stdin= ap(READ,0);
- common_stdinb= ap(READBIN,0);
- cook_stdin=ap(readvals(0,0),OFFSIDE);
- nill= cons(CONST,NIL);
- Void=make_id("()");
- id_type(Void)=void_t;
- id_val(Void)=constructor(0,Void);
- message=make_id("sys_message");
- main_id=make_id("main"); /* change to magic scripts 19.11.2013 */
- concat=make_id("concat");
- diagonalise=make_id("diagonalise");
- standardout=constructor(0,"Stdout");
- indent_fn=make_id("indent");
- outdent_fn=make_id("outdent");
- listdiff_fn=make_id("listdiff");
- shownum1=make_id("shownum1");
- showbool=make_id("showbool");
- showchar=make_id("showchar");
- showlist=make_id("showlist");
- showstring=make_id("showstring");
- showparen=make_id("showparen");
- showpair=make_id("showpair");
- showvoid=make_id("showvoid");
- showfunction=make_id("showfunction");
- showabstract=make_id("showabstract");
- showwhat=make_id("showwhat");
- primlib(); } /* sets up predefined ids, not referred to by RULES */
-
-void dieclean() /* called if evaluation is interrupted - see RULES */
-{ printf("<<...interrupt>>\n");
-#ifndef NOSTATSONINT
- outstats(); /* suppress in presence of segfault on ^C with /count */
-#endif
- exit(0);
-}
-
-/* the function process() creates a process and waits for it to die -
- returning 1 in the child and 0 in the parent - it is used in the
- evaluation command (see MIRANDA RULES) */
-process()
-{ word pid;
- sighandler oldsig;
- oldsig = signal(SIGINT,SIG_IGN);
- /* do not let parent receive interrupts intended for child */
- if(pid=fork())
- { /* parent */
- word status; /* see man 2 exit, wait, signal */
- if(pid== -1)
- { perror("UNIX error - cannot create process");
- return(0);
- }
- while(pid!=wait(&status));
- /* low byte of status is termination state of child, next byte is the
- (low order byte of the) exit status */
- if(WIFSIGNALED(status)) /* abnormal termination status */
- { char *cd=status&0200?" (core dumped)":"";
- char *pc=""; /* "probably caused by stack overflow\n";*/
- switch(WTERMSIG(status))
- { case SIGBUS: printf("\n<<...bus error%s>>\n%s",cd,pc); break;
- case SIGSEGV: printf("\n<<...segmentation fault%s>>\n%s",cd,pc); break;
- default: printf("\n<<...uncaught signal %d>>\n",WTERMSIG(status));
- } }
- /*if(status >>= 8)printf("\n(exit status %d)\n",status); */
- (void)signal(SIGINT,oldsig); /* restore interrupt status */
- return(0); }
- else return(1); /* child */
-}
-
-/* Notice that the MIRANDA system has a two-level interrupt structure.
- 1) Each evaluation (see RULES) is an interruptible process.
- 2) If the command loop is interrupted outside an evaluation or during
- compilation it reverts to the top level prompt - see set_jmp and
- signal(reset) in commandloop() */
-
-primdef(n,v,t) /* used by "primlib", see below */
-char *n;
-word v,t;
-{ word x;
- x= make_id(n);
- primenv=cons(x,primenv);
- id_val(x)= v;
- id_type(x)=t; }
-
-predef(n,v,t) /* used by "privlib" and "stdlib", see below */
-char *n;
-word v,t;
-{ word x;
- x= make_id(n);
- addtoenv(x);
- id_val(x)= isconstructor(x)?constructor(v,x):v;
- id_type(x)=t;
-}
-
-primlib() /* called by "mira_setup", this routine enters
- the primitive identifiers into the primitive environment */
-{ primdef("num",make_typ(0,0,synonym_t,num_t),type_t);
- primdef("char",make_typ(0,0,synonym_t,char_t),type_t);
- primdef("bool",make_typ(0,0,synonym_t,bool_t),type_t);
- primdef("True",1,bool_t); /* accessible only to 'finger' */
- primdef("False",0,bool_t); /* likewise - FIX LATER */
-}
-
-privlib() /* called when compiling <prelude>, adds some
- internally defined identifiers to the environment */
-{ extern word ltchar;
- predef("offside",OFFSIDE,ltchar); /* used by `indent' in prelude */
- predef("changetype",I,wrong_t); /* wrong_t to prevent being typechecked */
- predef("first",HD,wrong_t);
- predef("rest",TL,wrong_t);
-/* the following added to make prelude compilable without stdenv */
- predef("code",CODE,undef_t);
- predef("concat",ap2(FOLDR,APPEND,NIL),undef_t);
- predef("decode",DECODE,undef_t);
- predef("drop",DROP,undef_t);
- predef("error",ERROR,undef_t);
- predef("filter",FILTER,undef_t);
- predef("foldr",FOLDR,undef_t);
- predef("hd",HD,undef_t);
- predef("map",MAP,undef_t);
- predef("shownum",SHOWNUM,undef_t);
- predef("take",TAKE,undef_t);
- predef("tl",TL,undef_t);
-}
-
-stdlib() /* called when compiling <stdenv>, adds some
- internally defined identifiers to the environment */
-{ predef("arctan",ARCTAN_FN,undef_t);
- predef("code",CODE,undef_t);
- predef("cos",COS_FN,undef_t);
- predef("decode",DECODE,undef_t);
- predef("drop",DROP,undef_t);
- predef("entier",ENTIER_FN,undef_t);
- predef("error",ERROR,undef_t);
- predef("exp",EXP_FN,undef_t);
- predef("filemode",FILEMODE,undef_t);
- predef("filestat",FILESTAT,undef_t); /* added Feb 91 */
- predef("foldl",FOLDL,undef_t);
- predef("foldl1",FOLDL1,undef_t); /* new at release 2 */
- predef("hugenum",sto_dbl(DBL_MAX),undef_t);
- /* max_normal() if present returns same value (see <math.h>) */
- predef("last",LIST_LAST,undef_t);
- predef("foldr",FOLDR,undef_t);
- predef("force",FORCE,undef_t);
- predef("getenv",GETENV,undef_t);
- predef("integer",INTEGER,undef_t);
- predef("log",LOG_FN,undef_t);
- predef("log10",LOG10_FN,undef_t); /* new at release 2 */
- predef("merge",MERGE,undef_t); /* new at release 2 */
- predef("numval",NUMVAL,undef_t);
- predef("read",STARTREAD,undef_t);
- predef("readb",STARTREADBIN,undef_t);
- predef("seq",SEQ,undef_t);
- predef("shownum",SHOWNUM,undef_t);
- predef("showhex",SHOWHEX,undef_t);
- predef("showoct",SHOWOCT,undef_t);
- predef("showfloat",SHOWFLOAT,undef_t); /* new at release 2 */
- predef("showscaled",SHOWSCALED,undef_t); /* new at release 2 */
- predef("sin",SIN_FN,undef_t);
- predef("sqrt",SQRT_FN,undef_t);
- predef("system",EXEC,undef_t); /* new at release 2 */
- predef("take",TAKE,undef_t);
- predef("tinynum",mktiny(),undef_t); /* new at release 2 */
- predef("zip2",ZIP,undef_t); /* new at release 2 */
-}
-
-mktiny()
-{ volatile
- double x=1.0,x1=x/2.0;
- while(x1>0.0)x=x1,x1/=2.0;
- return(sto_dbl(x));
-}
-/* min_subnormal() if present returns same value (see <math.h>) */
-
-size(x) /* measures the size of a compiled expression */
-word x;
-{ word s;
- s= 0;
- while(tag[x]==CONS||tag[x]==AP)
- { s= s+1+size(hd[x]);
- x= tl[x]; }
- return(s); }
-
-makedump()
-{ char *obf=linebuf;
- FILE *f;
- (void)strcpy(obf,current_script);
- (void)strcpy(obf+strlen(obf)-1,obsuffix);
- f=fopen(obf,"w");
- if(!f){ printf("WARNING: CANNOT WRITE TO %s\n",obf);
- if(strcmp(current_script,PRELUDE)==0||
- strcmp(current_script,STDENV)==0)
- printf(
- "TO FIX THIS PROBLEM PLEASE GET SUPER-USER TO EXECUTE `mira'\n");
- if(making&&!make_status)make_status=1;
- return; }
- /* printf("dumping to %s\n",obf); /* DEBUG */
- unlinkme=obf;
- /* fchmod(fileno(f),0666); /* to make dumps writeable by all */ /* no! */
- setprefix(current_script);
- dump_script(files,f);
- unlinkme=NULL;
- fclose(f);
-}
-
-undump(t) /* restore t from dump, or recompile if necessary */
-char *t;
-{ extern word BAD_DUMP,CLASHES;
- if(!normal(t)&&!initialising)return loadfile(t);
- /* except for prelude, only .m files have dumps */
- char obf[pnlim];
- FILE *f;
- sighandler oldsig;
- word flen=strlen(t);
- time_t t1=fm_time(t),t2;
- if(flen>pnlim)
- { printf("sorry, pathname too long (limit=%d): %s\n",pnlim,t);
- return; } /* if anyone complains, should remove this limit */
- (void)strcpy(obf,t);
- (void)strcpy(obf+flen-1,obsuffix);
- t2=fm_time(obf);
- if(t2&&!t1)t2=0,unlink(obf); /* dump is orphan - remove */
- if(!t2||t2<t1) /* dump is nonexistent or older than source - ignore */
- { loadfile(t); return; }
- f=fopen(obf,"r");
- if(!f){ printf("cannot open %s\n",obf); loadfile(t); return; }
- current_script=t;
- loading=1;
- oldfiles=NIL;
- unload();
-/*if(!initialising)printf("undumping from %s\n",obf); /* DEBUG */
- if(!initialising&&!making) /* ie this is the main script */
- sigflag=0,
- oldsig=signal(SIGINT,(sighandler)sigdefer);
- /* can't take interrupt during load_script */
- files=load_script(f,t,NIL,NIL,!making&!initialising);
- fclose(f);
- if(BAD_DUMP)
- { extern word *stackp,*dstack;
- unlink(obf); unload(); CLASHES=NIL; stackp=dstack;
- printf("warning: %s contains incorrect data (file removed)\n",obf);
- if(BAD_DUMP== -1)printf("(obsolete dump format)\n"); else
- if(BAD_DUMP==1)printf("(wrong source file)\n"); else
- printf("(error %d)\n",BAD_DUMP); }
- if(!initialising&&!making) /* restore interrupt handler */
- (void)signal(SIGINT,oldsig);
- if(sigflag)sigflag=0,(*oldsig)(); /* take deferred interrupt */
- /*if(!initialising)printf("%s undumped\n",obf); /* DEBUG */
- if(CLASHES!=NIL)
- { if(ideep==0)printf("cannot load %s ",obf),
- printlist("due to name clashes: ",alfasort(CLASHES));
- unload();
- loading=0;
- return; }
- if(BAD_DUMP||src_update())loadfile(t);/* any sources modified since dump? */
- else
- if(initialising)
- { if(ND!=NIL||files==NIL) /* error in dump of PRELUDE */
- fprintf(stderr,"panic: %s contains errors\n",obf),
- exit(1); } /* beware of dangling else ! (whence {}) */
- else
- if(verbosity||magic||mkexports) /* for less silent making s/mkexports/making/ */
- if(files==NIL)printf("%s contains syntax error\n",t); else
- if(ND!=NIL)printf("%s contains undefined names or type errors\n",t); else
- if(!making&&!magic)printf("%s\n",t); /* added &&!magic 26.11.2019 */
- if(!files==NIL&&!making&!initialising)unfixexports();
- loading=0;
-}
-
-unlinkx(t) /* remove orphaned .x file */
-char *t;
-{ char *obf=linebuf;
- (void)strcpy(obf,t);
- (void)strcpy(obf+strlen(t)-1,obsuffix);
- if(!stat(obf,&buf))unlink(obf);
-}
-
-void fpe_error()
-{ if(compiling)
- { (void)signal(SIGFPE,(sighandler)fpe_error); /* reset SIGFPE trap */
-#ifdef sparc8
- fpsetmask(commonmask); /* to clear sticky bits */
-#endif
- syntax("floating point number out of range\n");
- SYNERR=0; longjmp(env,1);
- /* go straight back to commandloop - necessary because decoding very
- large numbers can cause huge no. of repeated SIGFPE exceptions */
- }
- else printf("\nFLOATING POINT OVERFLOW\n"),exit(1);
-}
-
-char fbuf[512];
-
-filecopy(fil) /* copy the file "fil" to standard out */
-char *fil;
-{ word in=open(fil,0),n;
- if(in== -1)return;
- while((n=read(in,fbuf,512))>0)write(1,fbuf,n);
- close(in);
-}
-
-filecp(fil1,fil2) /* copy file "fil1" to "fil2" (like `cp') */
-char *fil1,*fil2;
-{ word in=open(fil1,0),n;
- word out=creat(fil2,0644);
- if(in== -1||out== -1)return;
- while((n=read(in,fbuf,512))>0)write(out,fbuf,n);
- close(in);
- close(out);
-}
-
-/* to define winsize and TIOCGWINSZ for twidth() */
-#include <termios.h>
-#include <sys/ioctl.h>
-
-twidth() /* returns width (in columns) of current window, less 2 */
-{
-#ifdef TIOCGWINSZ
- static struct winsize tsize;
- ioctl(fileno(stdout),TIOCGWINSZ,&tsize);
- return (tsize.ws_col==0)?78:tsize.ws_col-2;
-#else
-#error TIOCGWINSZ undefined
-/* porting note: if you cannot find how to enable use of TIOCGWINSZ
- comment out the above #error line */
- return 78; /* give up, we will assume screen width to be 80 */
-#endif
-}
-
-/* was called when Miranda starts up and before /help, /aux
- to clear screen - suppressed Oct 2019 */
-/* clrscr()
-{ printf("\x1b[2J\x1b[H"); fflush(stdout);
-} */
-
-/* the following code tests if we are in a UTF-8 locale */
-
-#ifdef CYGWIN
-#include <windows.h>
-
-utf8test()
-{ return GetACP()==65001; }
-/* codepage 1252 is Windows version of Latin-1; 65001 is UTF-8 */
-
-#else
-
-utf8test()
-{ char *lang;
- if(!(lang=getenv("LC_CTYPE")))
- lang=getenv("LANG");
- if(lang&&
- (strstr(lang,"UTF-8")||strstr(lang,"UTF8")||
- strstr(lang,"utf-8")||strstr(lang,"utf8")))
- return 1;
- return 0;
-}
-#endif
-
-/* end of MIRANDA STEER */
-
diff --git a/new/trans.c b/new/trans.c
deleted file mode 100644
index e50eb8a..0000000
--- a/new/trans.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/* MIRANDA TRANS */
-/* performs translation to combinatory logic */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-#include "data.h"
-
- /* miscellaneous declarations */
-extern word nill,Void;
-extern word listdiff_fn,count_fn,from_fn;
-extern word diagonalise,concat;
-extern word lastname,initialising;
-extern word current_id,echoing;
-extern word errs;
-word newtyps=NIL; /* list of typenames declared in current script */
-word SGC=NIL; /* list of user defined sui-generis constructors */
-#define sui_generis(k) (/* k==Void|| */ member(SGC,k))
- /* 3/10/88 decision to treat `()' as lifted */
-
-abstract(x,e) /* abstraction of template x from compiled expression e */
-word x,e;
-{ switch(tag[x])
- { case ID:
- if(isconstructor(x))
- return(sui_generis(x)?ap(K,e):
- ap2(Ug,primconstr(x),e));
- else return(abstr(x,e));
- case CONS:
- if(hd[x]==CONST)
- if(tag[tl[x]]==INT)return(ap2(MATCHINT,tl[x],e));
- else return(ap2(MATCH,tl[x]==NILS?NIL:tl[x],e));
- else return(ap(U_,abstract(hd[x],abstract(tl[x],e))));
- case TCONS:
- case PAIR: /* tuples */
- return(ap(U,abstract(hd[x],abstract(tl[x],e))));
- case AP:
- if(sui_generis(head(x)))
- return(ap(Uf,abstract(hd[x],abstract(tl[x],e))));
- if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(ap2(ATLEAST,tl[hd[x]],abstract(tl[x],e)));
- while(tag[x]==AP)
- { e= abstract(tl[x],e);
- x= hd[x]; }
- /* now x must be a constructor */
- default: ; }
- if(isconstructor(x))
- return(ap2(Ug,primconstr(x),e));
- printf("error in declaration of \"%s\", undeclared constructor in pattern: ",
- get_id(current_id)); /* something funny here - fix later */
- out(stdout,x);
- printf("\n");
- return(NIL);
-}
-
-primconstr(x)
-word x;
-{ x=id_val(x);
- while(tag[x]!=CONSTRUCTOR)x=tl[x];
- return(x);
- /* => constructor values are of the form TRY f k where k is the
- original constructor value, and ! constructors are of the form
- MKSTRICT i k */
-}
-
-memb(l,x) /* tests if x is a member of list "l" - used in testing for
- repeated names - see rule for "v2" in MIRANDA RULES */
-word l,x;
-{ if(tag[x]==TVAR) /* type variable! */
- while(l!=NIL&&!eqtvar(hd[l],x))l= tl[l];
- else while(l!=NIL&&hd[l]!=x)l= tl[l];
- return(l!=NIL); }
-
-abstr(x,e) /* "bracket abstraction" of variable x from code e */
-word x,e;
-{ switch(tag[e])
- { case TCONS:
- case PAIR:
- case CONS: return(liscomb(abstr(x,hd[e]),abstr(x,tl[e])));
- case AP: if(hd[e]==BADCASE||hd[e]==CONFERROR)
- return(ap(K,e)); /* don't go inside error info */
- return(combine(abstr(x,hd[e]),abstr(x,tl[e])));
- case LAMBDA:
- case LET:
- case LETREC:
- case TRIES:
- case LABEL:
- case SHOW:
- case LEXER:
- case SHARE: fprintf(stderr,"impossible event in abstr (tag=%d)\n",tag[e]),
- exit(1);
- default: if(x==e||isvar_t(x)&&isvar_t(e)&&eqtvar(x,e))
- return(I); /* see note */
- return(ap(K,e));
-}} /* note - we allow abstraction wrt tvars - see genshfns() */
-
-#define mkindex(i) ((i)<256?(i):make(INT,i,0))
- /* will fall over if i >= IBASE */
-
-abstrlist(x,e) /* abstraction of list of variables x from code e */
-word x,e;
-{ switch(tag[e])
- { case TCONS:
- case PAIR:
- case CONS: return(liscomb(abstrlist(x,hd[e]),abstrlist(x,tl[e])));
- case AP: if(hd[e]==BADCASE||hd[e]==CONFERROR)
- return(ap(K,e)); /* don't go inside error info */
- else return(combine(abstrlist(x,hd[e]),abstrlist(x,tl[e])));
- case LAMBDA: case LET: case LETREC: case TRIES: case LABEL: case SHOW:
- case LEXER:
- case SHARE: fprintf(stderr,
- "impossible event in abstrlist (tag=%d)\n",tag[e]),
- exit(1);
- default: { word i=0;
- while(x!=NIL&&hd[x]!=e)i++,x=tl[x];
- if(x==NIL)return(ap(K,e));
- return(ap(SUBSCRIPT,mkindex(i))); }
-}}
-
-word rv_script=0; /* flags readvals in use (for garbage collector) */
-
-codegen(x) /* returns expression x with abstractions performed */
-word x;
-{ extern word debug,commandmode,cook_stdin,common_stdin,common_stdinb,rv_expr;
- switch(tag[x])
- { case AP: if(commandmode /* beware of corrupting lastexp */
- &&x!=cook_stdin&&x!=common_stdin&&x!=common_stdinb) /* but share $+ $- */
- return(make(AP,codegen(hd[x]),codegen(tl[x])));
- if(tag[hd[x]]==AP&&hd[hd[x]]==APPEND&&tl[hd[x]]==NIL)
- return(codegen(tl[x])); /* post typecheck reversal of HR bug fix */
- hd[x]=codegen(hd[x]); tl[x]=codegen(tl[x]);
- /* otherwise do in situ */
- return(tag[hd[x]]==AP&&hd[hd[x]]==G_ALT?leftfactor(x):x);
- case TCONS:
- case PAIR: return(make(CONS,codegen(hd[x]),codegen(tl[x])));
- case CONS: if(commandmode)
- return(make(CONS,codegen(hd[x]),codegen(tl[x])));
- /* otherwise do in situ (see declare) */
- hd[x]=codegen(hd[x]); tl[x]=codegen(tl[x]);
- return(x);
- case LAMBDA: return(abstract(hd[x],codegen(tl[x])));
- case LET: return(translet(hd[x],tl[x]));
- case LETREC: return(transletrec(hd[x],tl[x]));
- case TRIES: return(transtries(hd[x],tl[x]));
- case LABEL: return(codegen(tl[x]));
- case SHOW: return(makeshow(hd[x],tl[x]));
- case LEXER:
- { word r=NIL,uses_state=0;;
- while(x!=NIL)
- { word rule=abstr(mklexvar(0),codegen(tl[tl[hd[x]]]));
- rule=abstr(mklexvar(1),rule);
- if(!(tag[rule]==AP&&hd[rule]==K))uses_state=1;
- r=cons(cons(hd[hd[x]], /* start condition stuff */
- cons(ap(hd[tl[hd[x]]],NIL), /* matcher [] */
- rule)),
- r);
- x=tl[x]; }
- if(!uses_state) /* strip off (K -) from each rule */
- { for(x=r;x!=NIL;x=tl[x])tl[tl[hd[x]]]=tl[tl[tl[hd[x]]]];
- r = ap(LEX_RPT,ap(LEX_TRY,r)); }
- else r = ap(LEX_RPT1,ap(LEX_TRY1,r));
- return(ap(r,0)); } /* 0 startcond */
- case STARTREADVALS:
- if(ispoly(tl[x]))
- { extern word cook_stdin,polyshowerror,ND;
- printf("type error - %s used at polymorphic type :: [",
- cook_stdin&&x==hd[cook_stdin]?"$+":"readvals or $+");
- out_type(redtvars(tl[x])),printf("]\n");
- polyshowerror=1;
- if(current_id)
- ND=add1(current_id,ND),
- id_type(current_id)=wrong_t,
- id_val(current_id)=UNDEF;
- if(hd[x])sayhere(hd[x],1); }
- if(commandmode)rv_expr=1; else rv_script=1;
- return(x);
- case SHARE: if(tl[x]!= -1) /* arbitrary flag for already visited */
- hd[x]=codegen(hd[x]),tl[x]= -1;
- return(hd[x]);
- default: if(x==NILS)return(NIL);
- return(x); /* identifier, private name, or constant */
-}}
-
-word lfrule=0;
-
-leftfactor(x)
-
-/* grammar optimisations - x is of the form ap2(G_ALT,...)
- G_ALT(G_SEQ a b) a => G_SEQ a (G_ALT b G_UNIT)
- G_ALT(G_SEQ a b)(G_SEQ a c) => G_SEQ a (G_ALT b c)
- G_ALT(G_SEQ a b)(G_ALT a d) => G_ALT(G_SEQ a (G_ALT b G_UNIT)) d
- G_ALT(G_SEQ a b)(G_ALT(G_SEQ a c) d) => G_ALT(G_SEQ a (G_ALT b c)) d
-*/
-word x;
-{ word a,b,c,d;
- if(tag[c=tl[hd[x]]]==AP&&tag[hd[c]]==AP&&hd[hd[c]]==G_SEQ)
- a=tl[hd[c]],b=tl[c]; else return(x);
- if(same(a,d=tl[x]))
- { hd[x]=ap(G_SEQ,a), tl[x]=ap2(G_ALT,b,G_UNIT); lfrule++;
- /* printob("rule1: ",x); */
- return(x); }
- if(tag[d]==AP&&tag[hd[d]]==AP)
- c=hd[hd[d]]; else return(x);
- if(c==G_SEQ&&same(a,tl[hd[d]]))
- { c=tl[d],
- hd[x]=ap(G_SEQ,a), tl[x]=leftfactor(ap2(G_ALT,b,c)); lfrule++;
- /* printob("rule2: ",x); */
- return(x); }
- if(c!=G_ALT)return(x);
- if(same(a,c=tl[hd[d]]))
- { d=tl[d];
- hd[x]=ap(G_ALT,ap2(G_SEQ,a,ap2(G_ALT,b,G_UNIT)));
- tl[x]=d; lfrule++;
- /* printob("rule3: ",x); */
- return(leftfactor(x)); }
- if(tag[c]==AP&&tag[hd[c]]==AP&&hd[hd[c]]==G_SEQ
- &&same(a,tl[hd[c]]))
- { c=tl[c],d=tl[d],
- hd[x]=ap(G_ALT,ap2(G_SEQ,a,leftfactor(ap2(G_ALT,b,c))));
- tl[x]=d; lfrule++;
- /* printob("rule4: ",x); */
- return(leftfactor(x)); }
- return(x);
-}
-
-same(x,y) /* structural equality */
-word x,y;
-{ if(x==y)return(1);
- if(tag[x]==ATOM||tag[y]==ATOM||tag[x]!=tag[y])return(0);
- if(tag[x]<INT)return(hd[x]==hd[y]&&tl[x]==tl[y]);
- if(tag[x]>STRCONS)return(same(hd[x],hd[y])&&same(tl[x],tl[y]));
- return(hd[x]==hd[y]&&same(tl[x],tl[y])); /* INT..STRCONS */
-}
-
-static word was_poly;
-word polyshowerror;
-
-makeshow(here,type)
-word here,type;
-{ word f;
- extern word ND;
- was_poly=0; f=mkshow(0,0,type);
- /* printob("showfn=",f); /* DEBUG */
- if(here&&was_poly)
- { extern char *current_script;
- printf("type error in definition of %s\n",get_id(current_id));
- sayhere(here,0);
- printf(" use of \"show\" at polymorphic type ");
- out_type(redtvars(type));
- putchar('\n');
- id_type(current_id)=wrong_t;
- id_val(current_id)=UNDEF;
- polyshowerror=1;
- ND=add1(current_id,ND);
- was_poly=0; }
- return(f);
-}
-
-mkshow(s,p,t) /* build a show function appropriate to type t */
-word s,p,t; /* p is precedence - 0 for top level, 1 for internal */
- /* s flags special case invoked from genshfns */
-{ extern word shownum1,showbool,showchar,showlist,showstring,showparen,
- showvoid,showpair,showfunction,showabstract,showwhat;
- word a=NIL;
- while(tag[t]==AP)a=cons(tl[t],a),t=hd[t];
- switch(t)
- { case num_t: return(p?shownum1:SHOWNUM);
- case bool_t: return(showbool);
- case char_t: return(showchar);
- case list_t: if(hd[a]==char_t)return(showstring);
- return(ap(showlist,mkshow(s,0,hd[a])));
- case comma_t: return(ap(showparen,ap2(showpair,mkshow(s,0,hd[a]),
- mkshowt(s,hd[tl[a]]))));
- case void_t: return(showvoid);
- case arrow_t:return(showfunction);
- default: if(tag[t]==ID)
- { word r=t_showfn(t);
- if(r==0) /* abstype without show function */
- return(showabstract);
- if(r==showwhat) /* dont apply to parameter showfns */
- return(r);
- while(a!=NIL)r=ap(r,mkshow(s,1,hd[a])),a=tl[a];
- if(t_class(t)==algebraic_t)r=ap(r,p);
- return(r);
- /* note that abstype-showfns have only one precedence
- and show their components (if any) at precedence 1
- - if the latter is a problem could do parenthesis
- stripping */
- }
- if(isvar_t(t)){ if(s)return(t); /* see genshfns */
- was_poly=1;
- return(showwhat); }
- /* arbitrary - could be any strict function */
- if(tag[t]==STRCONS) /* pname */ /* DEBUG */
- { printf("warning - mkshow applied to suppressed type\n");
- return(showwhat); }
- else { printf("impossible event in mkshow ("),
- out_type(t), printf(")\n");
- return(showwhat); }
- }
-}
-
-mkshowt(s,t) /* t is a (possibly singleton) tuple type */
-word s,t; /* flags special call from genshfns */
-{ extern word showpair;
- if(tl[t]==void_t)return(mkshow(s,0,tl[hd[t]]));
- return(ap2(showpair,mkshow(s,0,tl[hd[t]]),mkshowt(s,tl[t])));
-}
-
-word algshfns=NIL; /* list of showfunctions for all algebraic types in scope
- (list of pnames) - needed to make dumps */
-
-genshfns() /* called after meta type check - create show functions for
- algebraic types */
-{ word s;
- for(s=newtyps;s!=NIL;s=tl[s])
- if(t_class(hd[s])==algebraic_t)
- { word f=0,r=t_info(hd[s]); /* r is list of constructors */
- word ush= tl[r]==NIL&&member(SGC,hd[r])?Ush1:Ush;
- for(;r!=NIL;r=tl[r])
- { word t=id_type(hd[r]),k=id_val(hd[r]);
- while(tag[k]!=CONSTRUCTOR)k=tl[k];/* lawful and !'d constructors*/
- /* k now holds constructor(i,hd[r]) */
- /* k=constructor(hd[k],datapair(get_id(tl[k]),0));
- /* this `freezes' the name of the constructor */
- /* incorrect, makes showfns immune to aliasing, should be
- done at mkshow time, not genshfn time - FIX LATER */
- while(isarrow_t(t))
- k=ap(k,mkshow(1,1,tl[hd[t]])),t=tl[t]; /* NB 2nd arg */
- k=ap(ush,k);
- while(iscompound_t(t))k=abstr(tl[t],k),t=hd[t];
- /* see kahrs.bug.m (this is the fix) */
- if(f)f=ap2(TRY,k,f);
- else f=k;
- }
- /* f~=0, placeholder types dealt with in specify() */
- pn_val(t_showfn(hd[s]))=f;
- algshfns=cons(t_showfn(hd[s]),algshfns);
- }
- else
- if(t_class(hd[s])==abstract_t) /* if showfn present check type is ok */
- if(t_showfn(hd[s]))
- if(!abshfnck(hd[s],id_type(t_showfn(hd[s]))))
- printf("warning - \"%s\" has type inappropriate for a show-function\n",
- get_id(t_showfn(hd[s]))),t_showfn(hd[s])=0;
-}
-
-abshfnck(t,f) /* t is an abstype, is f right type for its showfn? */
-word t,f;
-{ word n=t_arity(t),i=1;
- while(i<=n)
- if(isarrow_t(f))
- { word h=tl[hd[f]];
- if(!(isarrow_t(h)&&isvar_t(tl[hd[h]])&&gettvar(tl[hd[h]])==i
- &&islist_t(tl[h])&&tl[tl[h]]==char_t))return(0);
- i++,f=tl[f];
- } else return(0);
- if(!(isarrow_t(f)&&islist_t(tl[f])&&tl[tl[f]]==char_t))return(0);
- f=tl[hd[f]];
- while(iscompound_t(f)&&isvar_t(tl[f])&&gettvar(tl[f])==n--)f=hd[f];
- return(f==t);
-}
-
-transtries(id,x)
-word id,x; /* x is a list of alternative values, in reverse order */
-{ word r,h=0,earliest;
- if(fallible(hd[x])) /* add default last case */
- { word oldn=tag[id]==ID?datapair(get_id(id),0):0;
- r=ap(BADCASE,h=cons(oldn,0));
- /* 0 is placeholder for here-info */
- /* oldn omitted if id is pattern - FIX LATER */ }
- else r=codegen(earliest=hd[x]), x = tl[x];
- while(x!=NIL)r=ap2(TRY,codegen(earliest=hd[x]),r), x=tl[x];
- if(h)tl[h]=hd[earliest]; /* first line-no is the best marker */
- return(r);
-}
-
-translet(d,e) /* compile block with body e and def d */
-word d,e;
-{ word x=mklazy(d);
- return(ap(abstract(dlhs(x),codegen(e)),codegen(dval(x))));
-}
-/* nasty bug, codegen(dval(x)) was interfering with abstract(dlhs(x)...
- to fix made codegen on tuples be NOT in situ 20/11/88 */
-
-transletrec(dd,e) /* better method, using list indexing - Jan 88 */
-word e,dd;
-{ word lhs=NIL,rhs=NIL,pn=1;
- /* list of defs (x=e) is combined to listwise def `xs=es' */
- for(;dd!=NIL;dd=tl[dd])
- { word x=hd[dd];
- if(tag[dlhs(x)]==ID) /* couldn't be constructor, by grammar */
- lhs=cons(dlhs(x),lhs),
- rhs=cons(codegen(dval(x)),rhs);
- else { word i=0,ids,p=mkgvar(pn++); /* see note 1 */
- x=new_mklazy(x); ids=dlhs(x);
- lhs=cons(p,lhs),rhs=cons(codegen(dval(x)),rhs);
- for(;ids!=NIL;ids=tl[ids],i++)
- lhs=cons(hd[ids],lhs),
- rhs=cons(ap2(SUBSCRIPT,mkindex(i),p),rhs);
- }
- }
- if(tl[lhs]==NIL) /* singleton */
- return(ap(abstr(hd[lhs],codegen(e)),ap(Y,abstr(hd[lhs],hd[rhs]))));
- return(ap(abstrlist(lhs,codegen(e)),ap(Y,abstrlist(lhs,rhs))));
-}
-/* note 1: we here use the alternative `mklazy' transformation
- pat = e => x1=p!0;...;xn=p!(n-1);p=(lambda(pat)[xs])e|conferror;
- where p is a private name (need be unique only within a given letrec)
-*/
-
-mklazy(d) /* transforms local p=e to ids=($p.ids)e|conferror */
-word d;
-{ if(irrefutable(dlhs(d)))return(d);
-{ word ids=mktuple(dlhs(d));
- if(ids==NIL){ printf("impossible event in mklazy\n"); return(d); }
- dval(d)=ap2(TRY,ap(lambda(dlhs(d),ids),dval(d)),
- ap(CONFERROR,cons(dlhs(d),here_inf(dval(d)))));
- dlhs(d)=ids;
- return(d);
-}}
-
-new_mklazy(d) /* transforms local p=e to ids=($p.ids)e|conferror
- with ids a LIST (not tuple as formerly) */
-word d;
-{ word ids=get_ids(dlhs(d));
- if(ids==NIL){ printf("impossible event in new_mklazy\n"); return(d); }
- dval(d)=ap2(TRY,ap(lambda(dlhs(d),ids),dval(d)),
- ap(CONFERROR,cons(dlhs(d),here_inf(dval(d)))));
- dlhs(d)=ids;
- return(d);
-}
-
-here_inf(rhs) /* rhs is of form tries(id,val_list) */
-word rhs;
-{ word x=tl[rhs];
- while(tl[x]!=NIL)x=tl[x]; /* find earliest alternative */
- return(hd[hd[x]]); /* hd[x] is of form label(here_info,value) */
-}
-
-irrefutable(x) /* x built from suigeneris constr's and (unrepeated) names */
-word x;
-{ if(tag[x]==CONS)return(0); /* includes constants */
- if(isconstructor(x))return(sui_generis(x));
- if(tag[x]==ID)return(1);
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(0);
- return(irrefutable(hd[x])&&irrefutable(tl[x]));
-}
-
-combine(x,y)
-word x,y;
-{ word a,b,a1,b1;
- a= tag[x]==AP&&hd[x]==K;
- b= tag[y]==AP&&hd[y]==K;
- if(a&&b)return(ap(K,ap(tl[x],tl[y])));
- /* rule of K propagation */
- if(a&&y==I)return(tl[x]);
- /* rule 'eta */
- b1= tag[y]==AP&&tag[hd[y]]==AP&&hd[hd[y]]==B;
- if(a)if(b1)return(ap3(B1,tl[x],tl[hd[y]],tl[y])); else
- /* Mark Scheevel's new B1 introduction rule -- adopted Aug 83 */
- if(tag[tl[x]]==AP&&tag[hd[tl[x]]]==AP&&hd[hd[tl[x]]]==COND)
- return(ap3(COND,tl[hd[tl[x]]],ap(K,tl[tl[x]]),y));
- else return(ap2(B,tl[x],y));
- a1= tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==B;
- if(b)if(a1)if(tag[tl[hd[x]]]==AP&&hd[tl[hd[x]]]==COND)
- return(ap3(COND,tl[tl[hd[x]]],tl[x],y));
- else return(ap3(C1,tl[hd[x]],tl[x],tl[y]));
- else return(ap2(C,x,tl[y]));
- if(a1)if(tag[tl[hd[x]]]==AP&&hd[tl[hd[x]]]==COND)
- return(ap3(COND,tl[tl[hd[x]]],tl[x],y));
- else return(ap3(S1,tl[hd[x]],tl[x],y));
- else return(ap2(S,x,y)); }
-
-liscomb(x,y) /* the CONSy analogue of "combine" */
-word x,y;
-{ word a,b;
- a= tag[x]==AP&&hd[x]==K;
- b= tag[y]==AP&&hd[y]==K;
- if(a&&b)return(ap(K,cons(tl[x],tl[y])));
- /* K propagation again */
- if(a)if(y==I)return(ap(P,tl[x])); /* eta P - new rule added 20/11/88 */
- else return(ap2(B_p,tl[x],y));
- if(b)return(ap2(C_p,x,tl[y]));
- return(ap2(S_p,x,y)); }
-/* B_p,C_p,S_p are the CONSy analogues of B,C,S
- see MIRANDA REDUCE for their definitions */
-
-compzf(e,qq,diag) /* compile a zf expression with body e and qualifiers qq
- (listed in reverse order); diag is 0 for sequential
- and 1 for diagonalising zf expressions */
-word e,qq,diag;
-{ word hold=NIL,r=0,g1= -1; /* r is number of generators */
- while(qq!=NIL) /* unreverse qualifier list */
- { if(hd[hd[qq]]==REPEAT)qq=fixrepeats(qq);
- hold=cons(hd[qq],hold);
- if(hd[hd[qq]]==GUARD)r++; /* count filters */
- qq = tl[qq]; }
- for(qq=hold;qq!=NIL&&hd[hd[qq]]==GUARD;qq=tl[qq])r--; /* less leading filters */
- if(hd[hd[hold]]==GENERATOR)g1=tl[tl[hd[hold]]]; /* rhs of 1st generator */
- e=transzf(e,hold,diag?diagonalise:concat);
- /* diagonalise [ // ] comprehensions, but not [ | ] ones */
- if(diag)
- while(r--)e=ap(concat,e); /* see funny version of rule 3 below */
- return(e==g1?ap2(APPEND,NIL,e):e); /* test in g1 is to fix HR bug */
-}
-/* HR bug - if Rule 1 applied at outermost level, type info is lost
- eg [p|p<-3] ==> 3 (reported by Ham Richards, Nov 89)
-*/
-
-transzf(e,qq,conc) /* Bird and Wadler page 63 */
-word e,qq,conc;
-{ word q,q2;
- if(qq==NIL)return(cons(e,NIL));
- q=hd[qq];
- if(hd[q]==GUARD)
- return(ap3(COND,tl[q],transzf(e,tl[qq],conc),NIL));
- if(tl[qq]==NIL)
- if(hd[tl[q]]==e&&isvariable(e))return(tl[tl[q]]); /* Rule 1 */
- else if(irrefutable(hd[tl[q]]))
- return(ap2(MAP,lambda(hd[tl[q]],e),tl[tl[q]])); /* Rule 2 */
- else /* Rule 2 warped for refutable patterns */
- return(ap2(FLATMAP,lambda(hd[tl[q]],cons(e,NIL)),tl[tl[q]]));
- q2=hd[tl[qq]];
- if(hd[q2]==GUARD)
- if(conc==concat) /* Rule 3 */
- { tl[tl[q]]=ap2(FILTER,lambda(hd[tl[q]],tl[q2]),tl[tl[q]]);
- tl[qq]=tl[tl[qq]];
- return(transzf(e,qq,conc)); }
- else /* funny [//] version of Rule 3 to avoid creating weak lists */
- { e=ap3(COND,tl[q2],cons(e,NIL),NIL);
- tl[qq]=tl[tl[qq]];
- return(transzf(e,qq,conc)); } /* plus wrap result with concat */
- return(ap(conc,transzf(transzf(e,tl[qq],conc),cons(q,NIL),conc)));
- /* Rule 4 */
-}
-
-fixrepeats(qq) /* expands multi-lhs generators in zf expressions */
-word qq;
-{ word q = hd[qq];
- word rhs = q;
- qq = tl[qq];
- while(hd[rhs]==REPEAT)rhs = tl[tl[rhs]];
- rhs = tl[tl[rhs]]; /* rhs now contains the common right hand side */
- while(hd[q]==REPEAT)
- { qq = cons(cons(GENERATOR,cons(hd[tl[q]],rhs)),qq);
- q = tl[tl[q]];
- }
- return(cons(q,qq));
-} /* EFFICIENCY PROBLEM - rhs gets re-evaluated for each lhs, fix later */
- /* likewise re-typechecked, although this probably doesn't matter */
-
-lastlink(x) /* finds last link of a list -- needed with zf body elision */
-word x;
-{ while(tl[x]!=NIL)x=tl[x];
- return(x);
-}
-
-#define ischar(x) ((x)>=0&&(x)<=255)
-
-genlhs(x) /* x is an expression found on the lhs of <- and genlhs returns
- the corresponding pattern */
-word x;
-{ word hold;
- switch(tag[x])
- { case AP:
- if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS&&isnat(tl[x]))
- return(ap2(PLUS,tl[x],genlhs(tl[hd[x]]))); /* n+k pattern */
- case CONS:
- case TCONS:
- case PAIR:
- hold=genlhs(hd[x]); return(make(tag[x],hold,genlhs(tl[x])));
- case ID:
- if(member(idsused,x))return(cons(CONST,x));
- if(!isconstructor(x))idsused=cons(x,idsused); return(x);
- case INT: return(cons(CONST,x));
- case DOUBLE: syntax("floating point literal in pattern\n");
- return(nill);
- case ATOM: if(x==True||x==False||x==NILS||x==NIL||ischar(x))
- return(cons(CONST,x));
- default: syntax("illegal form on left of <-\n");
- return(nill);
-}}
-
-#ifdef OBSOLETE
-genexp(x) /* undoes effect of genlhs - sorry about that! (see qualifiers1)*/
-word x;
-{ switch(tag[x])
- { case AP: return(ap(genexp(hd[x]),genexp(tl[x])));
- case TCONS: return(tcons(genexp(hd[x]),genexp(tl[x])));
- case PAIR: return(pair(genexp(hd[x]),genexp(tl[x])));
- case CONS: return(hd[x]==CONST?tl[x]
- :cons(genexp(hd[x]),genexp(tl[x])));
- default: return(x); /* must be ID or constant */
-}}
-#endif
-
-word speclocs=NIL; /* list of cons(id,hereinfo) giving location of spec for
- ids both defined and specified - needed to locate errs
- in meta_tcheck, abstr_mcheck */
-getspecloc(x)
-word x;
-{ word s=speclocs;
- while(s!=NIL&&hd[hd[s]]!=x)s=tl[s];
- return(s==NIL?id_who(x):tl[hd[s]]); }
-
-declare(x,e) /* translates <pattern> = <exp> at top level */
-word x,e;
-{ if(tag[x]==ID&&!isconstructor(x))decl1(x,e);else
- { word bindings=scanpattern(x,x,share(tries(x,cons(e,NIL)),undef_t),
- ap(CONFERROR,cons(x,hd[e])));
- /* hd[e] is here-info */
- /* note creation of share node to force sharing on code generation
- and typechecking */
- if(bindings==NIL){ errs=hd[e];
- syntax("illegal lhs for definition\n");
- return; }
- lastname=0;
- while(bindings!=NIL)
- { word h;
- if(id_val(h=hd[hd[bindings]])!=UNDEF)
- { errs=hd[e]; nameclash(h); return; }
- id_val(h)=tl[hd[bindings]];
- if(id_who(h)!=NIL)speclocs=cons(cons(h,id_who(h)),speclocs);
- id_who(h)=hd[e]; /* here-info */
- if(id_type(h)==undef_t)addtoenv(h);
- bindings = tl[bindings];
- }
-}}
-
-scanpattern(p,x,e,fail) /* declare ids in x as components of `p=e', each as
- n = ($p.n)e, result is list of bindings */
-word p,x,e,fail;
-{ if(hd[x]==CONST||isconstructor(x))return(NIL);
- if(tag[x]==ID){ word binding=
- cons(x,ap2(TRY,ap(lambda(p,x),e),fail));
- return(cons(binding,NIL)); }
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(scanpattern(p,tl[x],e,fail));
- return(shunt(scanpattern(p,hd[x],e,fail),scanpattern(p,tl[x],e,fail)));
-}
-
-get_ids(x) /* return list of names in pattern x (without repetitions) */
-word x;
-{ if(hd[x]==CONST||isconstructor(x))return(NIL);
- if(tag[x]==ID)return(cons(x,NIL));
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(get_ids(tl[x]));
- return(UNION(get_ids(hd[x]),get_ids(tl[x])));
-}
-
-mktuple(x) /* extract tuple-structure of names from pattern x */
-word x;
-{ if(hd[x]==CONST||isconstructor(x))return(NIL);
- if(tag[x]==ID)return(x);
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(mktuple(tl[x]));
-{ word y=mktuple(tl[x]); x=mktuple(hd[x]);
- return(x==NIL?y:y==NIL?x:pair(x,y));
-}}
-
-decl1(x,e) /* declare name x to have the value denoted by e */
-word x,e;
-{ if(id_val(x)!=UNDEF&&lastname!=x)
- { errs=hd[e]; nameclash(x); return; }
- if(id_val(x)==UNDEF)
- { id_val(x)= tries(x,cons(e,NIL));
- if(id_who(x)!=NIL)speclocs=cons(cons(x,id_who(x)),speclocs);
- id_who(x)= hd[e]; /* here-info */
- if(id_type(x)==undef_t)addtoenv(x);
- } else
- if(!fallible(hd[tl[id_val(x)]]))
- errs=hd[e],
- printf("%ssyntax error: unreachable case in defn of \"%s\"\n",
- echoing?"\n":"",get_id(x)),
- acterror();
- else tl[id_val(x)]= cons(e,tl[id_val(x)]);
-/* multi-clause definitions are composed as tries(id,rhs_list)
- where id is included purely for diagnostic purposes
- note that rhs_list is reversed - put right by code generation */
-}
-
-fallible(e) /* e is "fallible" rhs - if not sure, says yes */
-word e;
-{ for(;;)
- { if(tag[e]==LABEL)e=tl[e];
- if(tag[e]==LETREC||tag[e]==LET)e=tl[e]; else
- if(tag[e]==LAMBDA)
- if(irrefutable(hd[e]))e=tl[e];
- else return(1); else
- if(tag[e]==AP&&tag[hd[e]]==AP&&tag[hd[hd[e]]]==AP&&hd[hd[hd[e]]]==COND)
- e=tl[e]; else
- return(e==FAIL); /* test for nested (COND a b FAIL) */
- }
-} /* NOTE
- When an rhs contains FAIL as a result of compiling an elseless guard set
- it is of the form
- XX ::= ap3(COND,a,b,FAIL) | let[rec](def[s],XX) | lambda(pat,XX)
- an rhs is fallible if
- 1) it is an XX, as above, or
- 2) it is of the form lambda(pat1,...,lambda(patn,e)...)
- where at least one of the patterns pati is refutable.
- */
-
-/* combinator to select i'th out of n args *//*
-k(i,n)
-int i,n;
-{ if(i==1)return(n==1?I:n==2?K:ap2(B,K,k(1,n-1)));
- if(i==2&&n==2)return(KI); /* redundant but saves space *//*
- return(ap(K,k(i-1,n-1)));
-} */
-
-#define arity_check if(t_arity(tf)!=arity)\
- printf("%ssyntax error: \
-wrong number of parameters for typename \"%s\" (%d expected)\n",\
- echoing?"\n":"",get_id(tf),t_arity(tf)),errs=here,acterror()
-
-decltype(tf,class,info,here) /* declare a user defined type */
-word tf,class,info,here;
-{ word arity=0;
- extern word errs;
- while(tag[tf]==AP)arity++,tf=hd[tf];
- if(class==synonym_t&&id_type(tf)==type_t&&t_class(tf)==abstract_t
- &&t_info(tf)==undef_t)
- { /* this is binding for declared but not yet bound abstract typename */
- arity_check;
- id_who(tf)=here;
- t_info(tf)=info;
- return; }
- if(class==abstract_t&&id_type(tf)==type_t&&t_class(tf)==synonym_t)
- { /* this is abstype declaration of already bound typename */
- arity_check;
- t_class(tf)=abstract_t;
- return; }
- if(id_val(tf)!=UNDEF)
- { errs=here; nameclash(tf); return; }
- if(class!=synonym_t)newtyps=add1(tf,newtyps);
- id_val(tf)=make_typ(arity,class==algebraic_t?make_pn(UNDEF):0,class,info);
- if(id_type(tf)!=undef_t){ errs=here; respec_error(tf); return; }
- else addtoenv(tf);
- id_who(tf)=here;
- id_type(tf)=type_t;
-}
-
-declconstr(x,n,t) /* declare x to be constructor number n of type t */
-word x,n,t; /* x must be an identifier */
-{ id_val(x)=constructor(n,x);
- if(n>>16)
- { syntax("algebraic type has too many constructors\n"); return; }
- if(id_type(x)!=undef_t){ errs=id_who(x); respec_error(x); return; }
- else addtoenv(x);
- id_type(x) = t;
-} /* the value of a constructor x is constructor(constr_tag,x)
- where constr_tag is a small natural number */
-
-/* #define DEPSDEBUG .
- /* switches on debugging printouts for dependency analysis in block() */
-#ifdef DEPSDEBUG
-pd(def)
-word def;
-{ out1(stdout,dlhs(def)); }
-
-pdlist(defs)
-word defs;
-{ putchar('(');
- for(;defs!=NIL;defs=tl[defs])
- pd(hd[defs]),printf(tl[defs]==NIL?"":",");
- putchar(')');
-}
-#endif
-
-block(defs,e,keep) /* semantics of "where" - performs dependency analysis */
-/* defs has form list(defn(pat,typ,val)), e is body of block */
-/* if `keep' hold together as single letrec */
-word defs,e,keep;
-{ word ids=NIL,deftoids=NIL,g=NIL,d;
- extern word SYNERR,detrop;
- /* return(letrec(defs,e)); /* release one semantics was just this */
- if(SYNERR)return(NIL); /* analysis falls over on empty patterns */
- for(d=defs;d!=NIL;d=tl[d]) /* first collect all ids defined in block */
- { word x = get_ids(dlhs(hd[d]));
- ids=UNION(ids,x);
- deftoids=cons(cons(hd[d],x),deftoids);
- }
- defs=sort(defs);
- for(d=defs;d!=NIL;d=tl[d]) /* now build dependency relation g */
- { word x=intersection(deps(dval(hd[d])),ids),y=NIL;
- for(;x!=NIL;x=tl[x]) /* replace each id by corresponding def */
- y=add1(invgetrel(deftoids,hd[x]),y);
- g=cons(cons(hd[d],add1(hd[d],y)),g);
- /* treat all defs as recursive for now */
- }
- g=reverse(g); /* keep in address order of first components */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("g=");
- for(;g1!=NIL;g1=tl[g1])
- pd(hd[hd[g1]]),putchar(':'),pdlist(tl[hd[g1]]),putchar(';');
- printf("\n"); }
-#endif
-/* g is list(cons(def,defs))
- where defs are all on which def immediately depends, plus self */
- g = tclos(g); /* now g is list(cons(def,ultdefs)) */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("tclos(g)=");
- for(;g1!=NIL;g1=tl[g1])
- pd(hd[hd[g1]]),putchar(':'),pdlist(tl[hd[g1]]),putchar(';');
- printf("\n"); }
-#endif
- { /* check for unused definitions */
- word x=intersection(deps(e),ids),y=NIL,*g1= &g;
- for(;x!=NIL;x=tl[x])
- { word d=invgetrel(deftoids,hd[x]);
- if(!member(y,d))y=UNION(y,getrel(g,d)); }
- defs=setdiff(defs,y); /* these are de trop */
- if(defs!=NIL)detrop=append1(detrop,defs);
- if(keep) /* if local polymorphism not required */
- return(letrec(y,e)); /* analysis was solely to find unwanted defs */
- /* remove redundant entries from g */
- /* no, leave in for typecheck - could remove afterwards
- while(*g1!=NIL&&defs!=NIL)
- if(hd[hd[*g1]]==hd[defs])*g1=tl[*g1]; else
- if(hd[hd[*g1]]<hd[defs])g1= &tl[*g1];
- else defs=tl[defs]; */
- }
- g = msc(g); /* g is list(defgroup,ultdefs) */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("msc(g)=");
- for(;g1!=NIL;g1=tl[g1])
- pdlist(hd[hd[g1]]),putchar(':'),pdlist(tl[hd[g1]]),putchar(';');
- printf("\n"); }
-#endif
- g = tsort(g); /* g is list(defgroup) in dependency order */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("tsort(g)=");
- for(;g1!=NIL;g1=tl[g1])
- pdlist(hd[g1]),putchar(';');
- printf("\n"); }
-#endif
- g = reverse(g); /* reconstruct block inside-first */
- while(g!=NIL)
- { if(tl[hd[g]]==NIL &&
- intersection(get_ids(dlhs(hd[hd[g]])),deps(dval(hd[hd[g]])))==NIL
- )e=let(hd[hd[g]],e); /* single non-recursive def */
- else e=letrec(hd[g],e);
- g=tl[g]; }
- return(e);
-}
-/* Implementation note:
- tsort will fall over if there is a non-list strong component because it
- was originally written on assumption that relation is over identifiers.
- Whence need to pretend all defs recursive until after tsort.
- Could do better - some defs may be subsidiary to others */
-
-tclos(r) /* fast transitive closure - destructive in r */
-word r; /* r is of form list(cons(x,xs)) */
-{ word r1;
- for(r1=r;r1!=NIL;r1=tl[r1])
- { word x= less1(tl[hd[r1]],hd[hd[r1]]);
- /* invariant x intersect tl[hd[r1]] = NIL */
- while(x!=NIL)
- { x=imageless(r,x,tl[hd[r1]]);
- tl[hd[r1]]=UNION(tl[hd[r1]],x); }
- }
- return(r);
-}
-
-getrel(r,x) /* r is list(cons(x,xs)) - return appropriate xs, else NIL */
-word r,x;
-{ while(r!=NIL&&hd[hd[r]]!=x)r=tl[r];
- return(r==NIL?NIL:tl[hd[r]]);
-}
-
-invgetrel(r,x) /* return first x1 such that `x1 r x' error if none found */
-word r,x;
-{ while(r!=NIL&&!member(tl[hd[r]],x))r=tl[r];
- if(r==NIL)fprintf(stderr,"impossible event in invgetrel\n"),exit(1);
- return(hd[hd[r]]);
-}
-
-
-imageless(r,y,z) /* image of set y in reln r, less set z */
-word r,y,z;
-{ word i=NIL;
- while(r!=NIL&&y!=NIL)
- if(hd[hd[r]]==hd[y])
- i=UNION(i,less(tl[hd[r]],z)),r=tl[r],y=tl[y]; else
- if(hd[hd[r]]<hd[y])r=tl[r];
- else y=tl[y];
- return(i);
-}
-
-less(x,y) /* non-destructive set difference x-y */
-word x,y;
-{ word r=NIL;
- while(x!=NIL&&y!=NIL)
- if(hd[x]==hd[y])x=tl[x],y=tl[y]; else
- if(hd[x]<hd[y])r=cons(hd[x],r),x=tl[x];
- else y=tl[y];
- return(shunt(r,x));
-}
-
-less1(x,a) /* non-destructive set difference x- {a} */
-word x,a;
-{ word r=NIL;
- while(x!=NIL&&hd[x]!=a)r=cons(hd[x],r),x=tl[x];
- return(shunt(r,x==NIL?NIL:tl[x]));
-}
-
-sort(x) /* into address order */
-word x;
-{ word a=NIL,b=NIL,hold=NIL;
- if(x==NIL||tl[x]==NIL)return(x);
- while(x!=NIL) /* split x */
- { hold=a,a=cons(hd[x],b),b=hold;
- x=tl[x]; }
- a=sort(a),b=sort(b);
- /* now merge two halves back together */
- while(a!=NIL&&b!=NIL)
- if(hd[a]<hd[b])x=cons(hd[a],x),a=tl[a];
- else x=cons(hd[b],x),b=tl[b];
- if(a==NIL)a=b;
- while(a!=NIL)x=cons(hd[a],x),a=tl[a];
- return(reverse(x));
-}
-
-sortrel(x) /* sort relation into address order of first components */
-word x; /* x is a list of cons(y,ys) */
-{ word a=NIL,b=NIL,hold=NIL;
- if(x==NIL||tl[x]==NIL)return(x);
- while(x!=NIL) /* split x */
- { hold=a,a=cons(hd[x],b),b=hold;
- x=tl[x]; }
- a=sortrel(a),b=sortrel(b);
- /* now merge two halves back together */
- while(a!=NIL&&b!=NIL)
- if(hd[hd[a]]<hd[hd[b]])x=cons(hd[a],x),a=tl[a];
- else x=cons(hd[b],x),b=tl[b];
- if(a==NIL)a=b;
- while(a!=NIL)x=cons(hd[a],x),a=tl[a];
- return(reverse(x));
-}
-
-specify(x,t,h) /* semantics of a "::" statement */
-word x,t,h; /* N.B. t not yet in reduced form */
-{ extern word showwhat;
- if(tag[x]!=ID&&t!=type_t){ errs=h;
- syntax("incorrect use of ::\n");
- return; }
- if(t==type_t)
- { word a=0;
- while(tag[x]==AP)a++,x=hd[x];
- if(!(id_val(x)==UNDEF&&id_type(x)==undef_t))
- { errs=h; nameclash(x); return; }
- id_type(x)=type_t;
- if(id_who(x)==NIL)id_who(x)=h; /* premise always true, see above */
- /* if specified and defined, locate by definition */
- id_val(x)=make_typ(a,showwhat,placeholder_t,NIL);/* placeholder type */
- addtoenv(x);
- newtyps=add1(x,newtyps);
- return; }
- if(id_type(x)!=undef_t){ errs=h; respec_error(x); return; }
- id_type(x)=t;
- if(id_who(x)==NIL)id_who(x)=h; /* as above */
- else speclocs=cons(cons(x,h),speclocs);
- if(id_val(x)==UNDEF)addtoenv(x);
-}
-
-respec_error(x) /* only one type spec per name allowed - IS THIS RIGHT? */
-word x;
-{ extern word primenv;
- if(echoing)putchar('\n');
- printf("syntax error: type of \"%s\" already declared%s\n",get_id(x),
- member(primenv,x)?" (in standard environment)":"");
- acterror();
-}
-
-nameclash(x) /* only one top level binding per name allowed */
-word x;
-{ extern word primenv;
- if(echoing)putchar('\n');
- printf("syntax error: nameclash, \"%s\" already defined%s\n",get_id(x),
- member(primenv,x)?" (in standard environment)":"");
- acterror();
-}
-
-nclashcheck(n,dd,hr) /* is n already bound in list of definitions dd */
-word n,dd,hr;
-{ while(dd!=NIL&&!nclchk(n,dlhs(hd[dd]),hr))dd=tl[dd];
-}
-
-nclchk(n,p,hr) /* is n already bound in pattern p */
-word n,p,hr;
-{ if(hd[p]==CONST)return(0);
- if(tag[p]==ID)
- { if(n!=p)return(0);
- if(echoing)putchar('\n');
- errs=hr,
- printf(
-"syntax error: conflicting definitions of \"%s\" in where clause\n",
- get_id(n)),
- acterror();
- return(1); }
- if(tag[p]==AP&&hd[p]==PLUS) /* hd of n+k pattern */
- return(0);
- return(nclchk(n,hd[p],hr)||nclchk(n,tl[p],hr));
-}
-
-transtypeid(x) /* recognises literal type constants - see RULES */
-word x;
-{ char *n=get_id(x);
- return(strcmp(n,"bool")==0?bool_t:
- strcmp(n,"num")==0?num_t:
- strcmp(n,"char")==0?char_t:
- x);
-}
-
-/* end of MIRANDA TRANS */
-
diff --git a/new/types.c b/new/types.c
deleted file mode 100644
index f20627f..0000000
--- a/new/types.c
+++ /dev/null
@@ -1,1613 +0,0 @@
-/* MIRANDA TYPECHECKER */
-
-/**************************************************************************
- * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
- * The Miranda system is distributed as free software under the terms in *
- * the file "COPYING" which is included in the distribution. *
- *------------------------------------------------------------------------*/
-
-#include "data.h"
-#include "big.h"
-word R=NIL; /* direct-and-indirect dependency graph */
-word TABSTRS=NIL; /* list of abstype declarations */
-word ND; /* undefined names used in script */
-word SBND; /* names specified but not defined (handled separately) */
-word FBS; /* list of bindings caused by parameterised %include's */
-word ATNAMES; /* global var set by abstr_check */
-word NT=NIL; /* undefined typenames used in script */
-word TYPERRS;
-word bnf_t=0;
-word current_id=0,lastloc=0,lineptr=0; /* used to locate type errors */
-word showchain=NIL; /* links together all occurrences of special forms (show)
- encountered during typecheck */
-extern word rfl;
-
-#include <setjmp.h>
-jmp_buf env1; /* for longjmp - see man (3) setjmp */
-
-checktypes() /* outcome indicated by setting of flags SYNERR, TYPERRS, ND */
-{ word s;
- extern word freeids,SYNERR,fnts;
- ATNAMES=TYPERRS=0;
- NT=R=SBND=ND=NIL; /* NT=R= added 4/6/88 */
- if(setjmp(env1)==1)goto L;
- if(rfl!=NIL)readoption();
- for(s=reverse(fil_defs(hd[files]));s!=NIL;s=tl[s])
- comp_deps(hd[s]); /* for each identifier in current script, compute
- dependencies to form R */
- R=tclos(sortrel(R));
- if(FBS!=NIL)mcheckfbs();
- abstr_mcheck(TABSTRS);
-L:if(TYPERRS)
- { /* badly formed types, so give up */
- TABSTRS=NT=R=NIL;
- printf("typecheck cannot proceed - compilation abandoned\n");
- SYNERR=1;
- return; }
- if(freeids!=NIL)redtfr(freeids);
- /* printgraph("dependency analysis:",R); /* for debugging */
- genshfns();
- if(fnts!=NIL)genbnft();
- R=msc(R);
- /* printgraph("strong components:",R); /* for debugging */
- s=tsort(R);
- /* printlist("topological sort:",s); /* for debugging */
- NT=R=NIL; /* must be invariant across the call */
- while(s!=NIL)infer_type(hd[s]),s=tl[s];
- checkfbs();
- while(TABSTRS!=NIL)
- abstr_check(hd[TABSTRS]),TABSTRS=tl[TABSTRS];
- if(SBND!=NIL)
- printlist("SPECIFIED BUT NOT DEFINED: ",alfasort(SBND)),SBND=NIL;
- fixshows();
- lastloc=0;
- return;
-}
-
-/* NOTES
- let element ::= id | list(id)
- let graph1 ::= list(cons(id,list(id)))
- let graph2 ::= list(cons(element,list(id)))
- we define:
- comp_deps(id)->builds R::graph1, direct dependencies
- R=tclos(sortrel(R))::graph1, direct and indirect dependencies
- msc(R)->collects maximal strong components in R, now R::graph2
- tsort(graph2)->list(element), topologically sorted
- infer_type(element)->fills in the id_type field(s) of element
-*/
-/* R occupies quadratic worst-case space - does anyone know a better way? */
-
-comp_deps(n) /* adds to R an entry of the form cons(n,RHS) where n is an
- identifier and RHS is a list of all the identifiers in the
- current script upon which n directly depends */
-/* it also meta-typechecks type specifications, and puts them in reduced
- form, as it goes */
-word n;
-{ word rhs=NIL,r;
- /* printf("comp_deps(%s)\n",get_id(n)); /* DEBUG */
- if(id_type(n)==type_t)
- { if(t_class(n)==algebraic_t)
- { r=t_info(n);
- while(r!=NIL) /* meta type check constructors */
- { current_id=hd[r];
- id_type(hd[r])=redtvars(meta_tcheck(id_type(hd[r])));
- r=tl[r]; }
- }
- else if(t_class(n)==synonym_t)
- current_id=n,t_info(n)=meta_tcheck(t_info(n));
- else if(t_class(n)==abstract_t)
- if(t_info(n)==undef_t)
- printf("error: script contains no binding for abstract typename\
- \"%s\"\n",get_id(n)),sayhere(id_who(n),1),TYPERRS++;
- else current_id=n,t_info(n)=meta_tcheck(t_info(n));
- /* placeholder types - no action */
- current_id=0;
- return; }
- if(tag[id_val(n)]==CONSTRUCTOR)return;
- /* primitive constructors require no type analysis */
- if(id_type(n)!=undef_t) /* meta typecheck spec, if present */
- { current_id=n;
- if(tag[id_type(n)]==CONS)
- { /* signature identifier */
- if(id_val(n)==UNDEF)SBND=add1(n,SBND);
- id_type(n)=redtvars(meta_tcheck(hd[id_type(n)]));
- current_id=0;
- return; } /* typechecked separately, under TABSTRS */
- id_type(n)=redtvars(meta_tcheck(id_type(n)));
- current_id=0; }
- if(id_val(n)==FREE)return; /* no further analysis required */
- if(id_val(n)==UNDEF) /* name specified but not defined */
- { SBND=add1(n,SBND); /* change of policy (as for undefined sigid, above) */
- return; } /* now not added to ND, so script can be %included */
- r=deps(id_val(n));
- while(r!=NIL)
- { if(id_val(hd[r])!=UNDEF&&id_type(hd[r])==undef_t)
- /* only defined names without explicitly assigned types
- cause dependency */
- rhs=add1(hd[r],rhs);
- r=tl[r]; }
- R=cons(cons(n,rhs),R);
-}
-
-tsort(g) /* topological sort - returns a list of the elements in the domain
- of relation g, in an order such that each element is preceded by everything
- it depends on */
-word g; /* the structure of g is "graph2" see NOTES above */
-{ word NP=NIL; /* NP is set of elements with no predecessor */
- word g1=g, r=NIL; /* r is result */
- g=NIL;
- while(g1!=NIL)
- { if(tl[hd[g1]]==NIL)NP=cons(hd[hd[g1]],NP);
- else g=cons(hd[g1],g);
- g1=tl[g1]; }
- while(NP!=NIL)
- { word D=NIL; /* ids to be removed from range of g */
- while(NP!=NIL)
- { r=cons(hd[NP],r);
- if(tag[hd[NP]]==ID)D=add1(hd[NP],D);
- else D=UNION(D,hd[NP]);
- NP=tl[NP]; }
- g1=g;g=NIL;
- while(g1!=NIL)
- { word rhs=setdiff(tl[hd[g1]],D);
- if(rhs==NIL)NP=cons(hd[hd[g1]],NP);
- else tl[hd[g1]]=rhs,g=cons(hd[g1],g);
- g1=tl[g1]; }
- }
- if(g!=NIL)fprintf(stderr,"error: impossible event in tsort\n");
- return(reverse(r));
-}
-
-msc(R) /* collects maximal strong components in R, converting it from "graph1"
- to "graph2" form - destructive in R */
-word R;
-{ word R1=R;
- while(R1!=NIL)
- { word *r= &tl[hd[R1]],l=hd[hd[R1]];
- if(remove1(l,r))
- { hd[hd[R1]]=cons(l,NIL);
- while(*r!=NIL)
- { word n=hd[*r],*R2= &tl[R1];
- while(*R2!=NIL&&hd[hd[*R2]]!=n)R2= &tl[*R2]; /* find n-entry in R */
- if(*R2!=NIL&&member(tl[hd[*R2]],l))
- { *r=tl[*r]; /* remove n from r */
- *R2=tl[*R2]; /* remove n's entry from R */
- hd[hd[R1]]=add1(n,hd[hd[R1]]);
- }
- else r= &tl[*r];
- }
- }
- R1=tl[R1];
- }
- return(R);
-}
-
-word meta_pending=NIL;
-
-meta_tcheck(t) /* returns type t with synonyms substituted out and checks that
- the result is well formed */
-word t;
-{ word tn=t,i=0;
- /* TO DO -- TIDY UP ERROR MESSAGES AND SET ERRLINE (ERRS) IF POSS */
- while(iscompound_t(tn))
- tl[tn]=meta_tcheck(tl[tn]),i++,tn=hd[tn];
- if(tag[tn]==STRCONS)goto L; /* patch to handle free type bindings */
- if(tag[tn]!=ID)
- { if(i>0&&(isvar_t(tn)||tn==bool_t||tn==num_t||tn==char_t))
- { TYPERRS++;
- if(tag[current_id]==DATAPAIR)
- locate_inc(),
- printf("badly formed type \""),out_type(t),
- printf("\" in binding for \"%s\"\n",(char *)hd[current_id]),
- printf("("),out_type(tn),printf(" has zero arity)\n");
- else
- printf("badly formed type \""),out_type(t),
- printf("\" in %s for \"%s\"\n",
- id_type(current_id)==type_t?"== binding":"specification",
- get_id(current_id)),
- printf("("),out_type(tn),printf(" has zero arity)\n"),
- sayhere(getspecloc(current_id),1);
- sterilise(t); }
- return(t); }
- if(id_type(tn)==undef_t&&id_val(tn)==UNDEF)
- { TYPERRS++;
- if(!member(NT,tn))
- { if(tag[current_id]==DATAPAIR)locate_inc();
- printf("undeclared typename \"%s\" ",get_id(tn));
- if(tag[current_id]==DATAPAIR)
- printf("in binding for %s\n",(char *)hd[current_id]);
- else sayhere(getspecloc(current_id),1);
- NT=add1(tn,NT); }
- return(t); }else
- if(id_type(tn)!=type_t||t_arity(tn)!=i)
- { TYPERRS++;
- if(tag[current_id]==DATAPAIR)
- locate_inc(),
- printf("badly formed type \""),out_type(t),
- printf("\" in binding for \"%s\"\n",(char *)hd[current_id]);
- else
- printf("badly formed type \""),out_type(t),
- printf("\" in %s for \"%s\"\n",
- id_type(current_id)==type_t?"== binding":"specification",
- get_id(current_id));
- if(id_type(tn)!=type_t)
- printf("(%s not defined as typename)\n",get_id(tn));
- else printf("(typename %s has arity %d)\n",get_id(tn),t_arity(tn));
- if(tag[current_id]!=DATAPAIR)
- sayhere(getspecloc(current_id),1);
- sterilise(t);
- return(t); }
-L:if(t_class(tn)!=synonym_t)return(t);
- if(member(meta_pending,tn))
- { TYPERRS++;/* report cycle */
- if(tag[current_id]==DATAPAIR)locate_inc();
- printf("error: cycle in type \"==\" definition%s ",
- meta_pending==NIL?"":"s");
- printelement(meta_pending); putchar('\n');
- if(tag[current_id]!=DATAPAIR)
- sayhere(id_who(tn),1);
- longjmp(env1,1); /* fatal error - give up */
-/* t_class(tn)=algebraic_t;t_info(tn)=NIL;
- /* to make sure we dont fall in here again! */
- return(t); }
- meta_pending=cons(tn,meta_pending);
- tn=NIL;
- while(iscompound_t(t))
- tn=cons(tl[t],tn),t=hd[t];
- t=meta_tcheck(ap_subst(t_info(t),tn));
- meta_pending=tl[meta_pending];
- return(t);
-}
-/* needless inefficiency - we recheck the rhs of a synonym every time we
- use it */
-
-sterilise(t) /* to prevent multiple reporting of metatype errors from
- namelist :: type */
-word t;
-{ if(tag[t]==AP)hd[t]=list_t,tl[t]=num_t;
-}
-
-word tvcount=1;
-#define NTV mktvar(tvcount++)
- /* brand new type variable */
-#define reset_SUBST (current_id=tvcount>=hashsize?clear_SUBST():0)
-
-infer_type(x) /* deduces the types of the identifiers in x - no result,
- works by filling in id_type fields */
-word x; /* x is an "element" */
-{ if(tag[x]==ID)
- { word t,oldte=TYPERRS;
- current_id=x;
- t = subst(etype(id_val(x),NIL,NIL));
- if(id_type(x)==undef_t)id_type(x)=redtvars(t);
- else /* x already has assigned type */
- if(!subsumes(t,instantiate(id_type(x))))
- { TYPERRS++;
- printf("incorrect declaration ");
- sayhere(getspecloc(x),1); /* or: id_who(x) to locate defn */
- printf("specified, "); report_type(x); putchar('\n');
- printf("inferred, %s :: ",get_id(x)); out_type(redtvars(t));
- putchar('\n'); }
- if(TYPERRS>oldte)id_type(x)=wrong_t,
- id_val(x)=UNDEF,
- ND=add1(x,ND);
- reset_SUBST; }
- else{ /* recursive group of names */
- word x1,oldte,ngt=NIL;
- for(x1=x;x1!=NIL;x1=tl[x1])
- ngt=cons(NTV,ngt),
- id_type(hd[x1])=ap(bind_t,hd[ngt]);
- for(x1=x;x1!=NIL;x1=tl[x1])
- { oldte=TYPERRS,
- current_id=hd[x1],
- unify(tl[id_type(hd[x1])],etype(id_val(hd[x1]),NIL,ngt));
- if(TYPERRS>oldte)
- id_type(hd[x1])=wrong_t,
- id_val(hd[x1])=UNDEF,ND=add1(hd[x1],ND); }
- for(x1=x;x1!=NIL;x1=tl[x1])
- if(id_type(hd[x1])!=wrong_t)
- id_type(hd[x1])=redtvars(ult(tl[id_type(hd[x1])]));
- reset_SUBST;
- }
-}
-
-word hereinc; /* location of currently-being-processed %include */
-word lasthereinc;
-
-mcheckfbs()
-{ word ff,formals,n;
- lasthereinc=0;
- for(ff=FBS;ff!=NIL;ff=tl[ff])
- { hereinc=hd[hd[FBS]];
- for(formals=tl[hd[ff]];formals!=NIL;formals=tl[formals])
- { word t=tl[tl[hd[formals]]];
- if(t!=type_t)continue;
- current_id=hd[tl[hd[formals]]]; /* nb datapair(orig,0) not id */
- t_info(hd[hd[formals]])=meta_tcheck(t_info(hd[hd[formals]]));
- /*ATNAMES=cons(hd[hd[formals]],ATNAMES?ATNAMES:NIL); */
- current_id=0;
- }
- if(TYPERRS)return; /* to avoid misleading error messages */
- for(formals=tl[hd[ff]];formals!=NIL;formals=tl[formals])
- { word t=tl[tl[hd[formals]]];
- if(t==type_t)continue;
- current_id=hd[tl[hd[formals]]]; /* nb datapair(orig,0) not id */
- tl[tl[hd[formals]]]=redtvars(meta_tcheck(t));
- current_id=0;
- }
- /* above double traverse is very inefficient way of doing types first
- would be better to have bindings sorted in this order beforehand */
- }
- /* all imported names must now have their types reduced to
- canonical form wrt the parameter bindings */
- /* alternative method - put info in ATNAMES, see above and in abstr_check */
- /* a problem with this is that types do not print in canonical form */
- if(TYPERRS)return;
- for(ff=tl[files];ff!=NIL;ff=tl[ff])
- for(formals=fil_defs(hd[ff]);formals!=NIL;formals=tl[formals])
- if(tag[n=hd[formals]]==ID)
- if(id_type(n)==type_t)
- { if(t_class(n)==synonym_t)t_info(n)=meta_tcheck(t_info(n)); }
- else id_type(n)=redtvars(meta_tcheck(id_type(n)));
-} /* wasteful if many includes */
-
-redtfr(x) /* ensure types of freeids are in reduced form */
-word x;
-{ for(;x!=NIL;x=tl[x])
- tl[tl[hd[x]]] = id_type(hd[hd[x]]);
-}
-
-checkfbs()
-/* FBS is list of entries of form cons(hereinfo,formals) where formals
- has elements of form cons(id,cons(datapair(orig,0),type)) */
-{ word oldte=TYPERRS,formals;
- lasthereinc=0;
- for(;FBS!=NIL;FBS=tl[FBS])
- for(hereinc=hd[hd[FBS]],formals=tl[hd[FBS]];
- formals!=NIL;formals=tl[formals])
- { word t,t1=fix_type(tl[tl[hd[formals]]]);
- if(t1==type_t)continue;
- current_id=hd[tl[hd[formals]]]; /* nb datapair(orig,0) not id */
- t = subst(etype(the_val(hd[hd[formals]]),NIL,NIL));
- if(!subsumes(t,instantiate(t1)))
- { TYPERRS++;
- locate_inc();
- printf("binding for parameter `%s' has wrong type\n",
- (char *)hd[current_id]);
- printf( "required :: "); out_type(tl[tl[hd[formals]]]);
- printf("\n actual :: "); out_type(redtvars(t));
- putchar('\n'); }
- the_val(hd[hd[formals]])=codegen(the_val(hd[hd[formals]])); }
- if(TYPERRS>oldte)
- { /* badly typed parameter bindings, so give up */
- extern word SYNERR;
- TABSTRS=NT=R=NIL;
- printf("compilation abandoned\n");
- SYNERR=1; }
- reset_SUBST;
-}
-
-fix_type(t,x) /* substitute out any indirected typenames in t */
-word t,x;
-{ switch(tag[t])
- { case AP:
- case CONS: tl[t]=fixtype(tl[t],x);
- hd[t]=fixtype(hd[t],x);
- default: return(t);
- case STRCONS: while(tag[pn_val(t)]!=CONS)t=pn_val(t);/*at most twice*/
- return(t);
- }
-}
-
-locate_inc()
-{ if(lasthereinc==hereinc)return;
- printf("incorrect %%include directive ");
- sayhere(lasthereinc=hereinc,1);
-}
-
-abstr_mcheck(tabstrs) /* meta-typecheck abstract type declarations */
-word tabstrs;
-{ while(tabstrs!=NIL)
- { word atnames=hd[hd[tabstrs]],sigids=tl[hd[tabstrs]],rtypes=NIL;
- if(cyclic_abstr(atnames))return;
- while(sigids!=NIL) /* compute representation types */
- { word rt=rep_t(id_type(hd[sigids]),atnames);
- /*if(rt==id_type(hd[sigids]))
- printf("abstype declaration error: \"%s\" has a type unrelated to \
-the abstraction\n",get_id(hd[sigids])),
- sayhere(getspecloc(hd[sigids]),1),
- TYPERRS++; /* suppressed June 89, see karen.m, secret.m */
- rtypes=cons(rt,rtypes);
- sigids=tl[sigids]; }
- rtypes=reverse(rtypes);
- hd[hd[tabstrs]]=cons(hd[hd[tabstrs]],rtypes);
- tabstrs=tl[tabstrs];
- }
-}
-
-abstr_check(x) /* typecheck the implementation equations of a type abstraction
- with the given signature */
-word x;
-{ word rtypes=tl[hd[x]],sigids=tl[x];
-/*int holdat=ATNAMES;
- ATNAMES=shunt(hd[hd[x]],ATNAMES); */
- ATNAMES=hd[hd[x]];
- txchange(sigids,rtypes); /* install representation types */
- /* report_types("concrete signature:\n",sigids); /* DEBUG */
- for(x=sigids;x!=NIL;x=tl[x])
- { word t,oldte=TYPERRS;
- current_id=hd[x];
- t=subst(etype(id_val(hd[x]),NIL,NIL));
- if(!subsumes(t,instantiate(id_type(hd[x]))))
- { TYPERRS++;
- printf("abstype implementation error\n");
- printf("\"%s\" is bound to value of type: ",get_id(hd[x]));
- out_type(redtvars(t));
- printf("\ntype expected: ");
- out_type(id_type(hd[x]));
- putchar('\n');
- sayhere(id_who(hd[x]),1); }
- if(TYPERRS>oldte)
- id_type(hd[x])=wrong_t,id_val(hd[x])=UNDEF,ND=add1(hd[x],ND);
- reset_SUBST; }
- /* restore the abstract types - for "finger" */
- for(x=sigids;x!=NIL;x=tl[x],rtypes=tl[rtypes])
- if(id_type(hd[x])!=wrong_t)id_type(hd[x])=hd[rtypes];
- ATNAMES= /* holdat */ 0;
-}
-
-cyclic_abstr(atnames) /* immediately-cyclic acts of dta are illegal */
-word atnames;
-{ word x,y=NIL;
- for(x=atnames;x!=NIL;x=tl[x])y=ap(y,t_info(hd[x]));
- for(x=atnames;x!=NIL;x=tl[x])
- if(occurs(hd[x],y))
- { printf("illegal type abstraction: cycle in \"==\" binding%s ",
- tl[atnames]==NIL?"":"s");
- printelement(atnames); putchar('\n');
- sayhere(id_who(hd[x]),1);
- TYPERRS++; return(1); }
- return(0);
-}
-
-txchange(ids,x) /* swap the id_type of each id with the corresponding type
- in the list x */
-word ids,x;
-{ while(ids!=NIL)
- { word t=id_type(hd[ids]);
- id_type(hd[ids])=hd[x],hd[x]=t;
- ids=tl[ids],x=tl[x]; }
-}
-
-report_type(x)
-word x;
-{ printf("%s",get_id(x));
- if(id_type(x)==type_t)
- if(t_arity(x)>5)printf("(arity %d)",t_arity(x));
- else { word i,j;
- for(i=1;i<=t_arity(x);i++)
- { putchar(' ');
- for(j=0;j<i;j++)putchar('*'); }
- }
- printf(" :: ");
- out_type(id_type(x));
-}
-
-report_types(header,x)
-char *header;
-word x;
-{ printf("%s",header);
- while(x!=NIL)
- report_type(hd[x]),putchar(';'),x=tl[x];
- putchar('\n');
-}
-
-typesfirst(x) /* rearrange list of ids to put types first */
-word x;
-{ word *y= &x,z=NIL;
- while(*y!=NIL)
- if(id_type(hd[*y])==type_t)
- z=cons(hd[*y],z),*y=tl[*y];
- else y= &tl[*y];
- return(shunt(z,x));
-}
-
-rep_t1(T,L) /* computes the representation type corresponding to T, wrt the
- abstract typenames in L */
- /* will need to apply redtvars to result, see below */
- /* if no substitutions found, result is identically T */
-word T,L;
-{ word args=NIL,t1,new=0;
- for(t1=T;iscompound_t(t1);t1=hd[t1])
- { word a=rep_t1(tl[t1],L);
- if(a!=tl[t1])new=1;
- args=cons(a,args); }
- if(member(L,t1))return(ap_subst(t_info(t1),args));
- /* call to redtvars removed 26/11/85
- leads to premature normalisation of subterms */
- if(!new)return(T);
- while(args!=NIL)
- t1=ap(t1,hd[args]),args=tl[args];
- return(t1);
-}
-
-rep_t(T,L) /* see above */
-word T,L;
-{ word t=rep_t1(T,L);
- return(t==T?t:redtvars(t));
-}
-
-type_of(x) /* returns the type of expression x, in reduced form */
-word x;
-{ word t;
- TYPERRS=0;
- t=redtvars(subst(etype(x,NIL,NIL)));
- fixshows();
- if(TYPERRS>0)t=wrong_t;
- return(t);
-}
-
-checktype(x) /* is expression x well-typed ? */
- /* not currently used */
-word x;
-{ TYPERRS=0;
- etype(x,NIL,NIL);
- reset_SUBST;
- return(!TYPERRS);
-}
-
-#define bound_t(t) (iscompound_t(t)&&hd[t]==bind_t)
-#define tf(a,b) ap2(arrow_t,a,b)
-#define tf2(a,b,c) tf(a,tf(b,c))
-#define tf3(a,b,c,d) tf(a,tf2(b,c,d))
-#define tf4(a,b,c,d,e) tf(a,tf3(b,c,d,e))
-#define lt(a) ap(list_t,a)
-#define pair_t(x,y) ap2(comma_t,x,ap2(comma_t,y,void_t))
-
-word tfnum,tfbool,tfbool2,tfnum2,tfstrstr,tfnumnum,ltchar,
- tstep,tstepuntil;
-
-tsetup()
-{ tfnum=tf(num_t,num_t);
- tfbool=tf(bool_t,bool_t);
- tfnum2=tf(num_t,tfnum);
- tfbool2=tf(bool_t,tfbool);
- ltchar=lt(char_t);
- tfstrstr=tf(ltchar,ltchar);
- tfnumnum=tf(num_t,num_t);
- tstep=tf2(num_t,num_t,lt(num_t));
- tstepuntil=tf(num_t,tstep);
-}
-
-word exec_t=0,read_t=0,filestat_t=0; /* set lazily, when used */
-
-genlstat_t() /* type of %lex state */
-{ return(pair_t(num_t,num_t)); }
-
-genbnft() /* if %bnf used, find out input type of parsing fns */
-{ word bnftokenstate=findid("bnftokenstate");
- if(bnftokenstate!=NIL&&id_type(bnftokenstate)==type_t)
- if(t_arity(bnftokenstate)==0)
- bnf_t=t_class(bnftokenstate)==synonym_t?
- t_info(bnftokenstate):bnftokenstate;
- else printf("warning - bnftokenstate has arity>0 (ignored by parser)\n"),
- bnf_t=void_t;
- else bnf_t=void_t; /* now bnf_t holds the state type */
- bnf_t=ap2(comma_t,ltchar,ap2(comma_t,bnf_t,void_t));
-} /* the input type for parsers is lt(bnf_t)
- note that tl[hd[tl[bnf_t]]] holds the state type */
-
-extern word col_fn;
-
-checkcolfn() /* if offside rule used, check col_fn has right type */
-{ word t=id_type(col_fn),f=tf(tl[hd[tl[bnf_t]]],num_t);
- if(t==undef_t||t==wrong_t
- /* will be already reported - do not generate further typerrs
- in both cases col_fn will behave as undefined name */
- ||subsumes(instantiate(t),f))
- { col_fn=0; return; } /* no further action required */
- printf("`bnftokenindentation' has wrong type for use in offside rule\n");
- printf("type required :: "); out_type(f); putchar('\n');
- printf(" actual type :: "); out_type(t); putchar('\n');
- sayhere(getspecloc(col_fn),1);
- TYPERRS++;
- col_fn= -1; /* error flag */
-} /* note that all parsing fns get type wrong_t if offside rule used
- anywhere and col_fn has wrong type - strictly this is overkill */
-
-etype(x,env,ngt) /* infer a type for an expression, by using unification */
-word x,env; /* env is list of local bindings of variables to types */
-word ngt; /* ngt is list of non-generic type variables */
-{ word a,b,c,d; /* initialise to 0 ? */
- switch(tag[x])
- { case AP: if(hd[x]==BADCASE||hd[x]==CONFERROR)return(NTV);
- /* don't type check insides of error messages */
- { word ft=etype(hd[x],env,ngt),at=etype(tl[x],env,ngt),rt=NTV;
- if(!unify1(ft,ap2(arrow_t,at,rt)))
- { ft=subst(ft);
- if(isarrow_t(ft))
- if(tag[hd[x]]==AP&&hd[hd[x]]==G_ERROR)
- type_error8(at,tl[hd[ft]]);
- else
- type_error("unify","with",at,tl[hd[ft]]);
- else type_error("apply","to",ft,at);
- return(NTV); }
- return(rt); }
- case CONS: { word ht=etype(hd[x],env,ngt),rt=etype(tl[x],env,ngt);
- if(!unify1(ap(list_t,ht),rt))
- { type_error("cons","to",ht,rt);
- return(NTV); }
- return(rt); }
- case LEXER: { word hold=lineptr;
- lineptr=hd[tl[tl[hd[x]]]];
- tl[tl[hd[x]]]=tl[tl[tl[hd[x]]]];/*discard label(hereinf,-)*/
- a=etype(tl[tl[hd[x]]],env,ngt);
- while((x=tl[x])!=NIL)
- { lineptr=hd[tl[tl[hd[x]]]];
- tl[tl[hd[x]]]=tl[tl[tl[hd[x]]]];/*discard label... */
- if(!unify1(a,b=etype(tl[tl[hd[x]]],env,ngt)))
- { type_error7(a,b);
- lineptr=hold;
- return(NTV); }
- }
- lineptr=hold;
- return(tf(ltchar,lt(a))); }
- case TCONS: return(ap2(comma_t,etype(hd[x],env,ngt),
- etype(tl[x],env,ngt)));
- case PAIR: return(ap2(comma_t,etype(hd[x],env,ngt),
- ap2(comma_t,etype(tl[x],env,ngt),void_t)));
- case DOUBLE:
- case INT: return(num_t);
- case ID: a=env;
- while(a!=NIL) /* take local binding, if present */
- if(hd[hd[a]]==x)
- return(linst(tl[hd[a]]=subst(tl[hd[a]]),ngt));
- else a=tl[a];
- a=id_type(x); /* otherwise pick up global binding */
- if(bound_t(a))return(tl[a]);
- if(a==type_t)type_error1(x);
- if(a==undef_t)
- { extern word commandmode;
- if(commandmode)type_error2(x);
- else
- if(!member(ND,x)) /* report first occurrence only */
- { if(lineptr)sayhere(lineptr,0);
- else if(tag[current_id]==DATAPAIR) /* see checkfbs */
- locate_inc();
- printf("undefined name \"%s\"\n",get_id(x));
- ND=add1(x,ND); }
- return(NTV); }
- if(a==wrong_t)return(NTV);
- return(instantiate(ATNAMES?rep_t(a,ATNAMES):a));
- case LAMBDA: a=NTV; b=NTV;
- d=cons(a,ngt);
- c=conforms(hd[x],a,env,d);
- if(c==-1||!unify(b,etype(tl[x],c,d)))return(NTV);
- return(tf(a,b));
- case LET: { word e,def=hd[x];
- a=NTV,e=conforms(dlhs(def),a,env,cons(a,ngt));
- current_id=cons(dlhs(def),current_id);
- c=lineptr; lineptr=dval(def);
- b = unify(a,etype(dval(def),env,ngt));
- lineptr=c;
- current_id=tl[current_id];
- if(e==-1||!b)return(NTV);
- return(etype(tl[x],e,ngt)); }
- case LETREC: { word e=env,s=NIL;
- a=NIL; c=ngt;
- for(d=hd[x];d!=NIL;d=tl[d])
- if(dtyp(hd[d])==undef_t)
- a=cons(hd[d],a), /* unspecified defs */
- dtyp(hd[d])=(b=NTV),
- c=cons(b,c), /* collect non-generic tvars */
- e=conforms(dlhs(hd[d]),b,e,c);
- else dtyp(hd[d])=meta_tcheck(dtyp(hd[d])),
- /* should do earlier, and locate errs properly*/
- s=cons(hd[d],s), /* specified defs */
- e=cons(cons(dlhs(hd[d]),dtyp(hd[d])),e);
- if(e==-1)return(NTV);
- b=1;
- for(;a!=NIL;a=tl[a])
- { current_id=cons(dlhs(hd[a]),current_id);
- d=lineptr; lineptr=dval(hd[a]);
- b &= unify(dtyp(hd[a]),etype(dval(hd[a]),e,c));
- lineptr=d; current_id=tl[current_id]; }
- for(;s!=NIL;s=tl[s])
- { current_id=cons(dlhs(hd[s]),current_id);
- d=lineptr; lineptr=dval(hd[s]);
- if(!subsumes(a=etype(dval(hd[s]),e,ngt),
- linst(dtyp(hd[s]),ngt)))
- /* would be better to set lineptr to spec here */
- b=0,type_error6(dlhs(hd[s]),dtyp(hd[s]),a);
- lineptr=d; current_id=tl[current_id]; }
- if(!b)return(NTV);
- return(etype(tl[x],e,ngt)); }
- case TRIES: { word hold=lineptr;
- a=NTV;
- x=tl[x];
- while(x!=NIL&&(lineptr=hd[hd[x]],
- unify(a,etype(tl[hd[x]],env,ngt)))
- )x=tl[x];
- lineptr=hold;
- if(x!=NIL)return(NTV);
- return(a); }
- case LABEL: { word hold=lineptr,t;
- lineptr=hd[x];
- t=etype(tl[x],env,ngt);
- lineptr=hold;
- return(t); }
- case STARTREADVALS: if(tl[x]==0)
- hd[x]=lineptr, /* insert here-info */
- tl[x]=NTV,
- showchain=cons(x,showchain);
- return(tf(ltchar,lt(tl[x])));
- case SHOW: hd[x]=lineptr; /* insert here-info */
- showchain=cons(x,showchain);
- return(tf(tl[x]=NTV,ltchar));
- case SHARE: if(tl[x]==undef_t)
- { word h=TYPERRS;
- tl[x]=subst(etype(hd[x],env,ngt));
- if(TYPERRS>h)hd[x]=UNDEF,tl[x]=wrong_t; }
- if(tl[x]==wrong_t)
- { TYPERRS++; return(NTV); }
- return(tl[x]);
- case CONSTRUCTOR: a=id_type(tl[x]);
- return(instantiate(ATNAMES?rep_t(a,ATNAMES):a));
- case UNICODE: return(char_t);
- case ATOM: if(x<256)return(char_t);
- switch(x)
- {
- case S:a=NTV,b=NTV,c=NTV;
- d=tf3(tf2(a,b,c),tf(a,b),a,c);
- return(d);
- case K:a=NTV,b=NTV;
- return(tf2(a,b,a));
- case Y:a=NTV;
- return(tf(tf(a,a),a));
- case C:a=NTV,b=NTV,c=NTV;
- return(tf3(tf2(a,b,c),b,a,c));
- case B:a=NTV,b=NTV,c=NTV;
- return(tf3(tf(a,b),tf(c,a),c,b));
- case FORCE:
- case G_UNIT:
- case G_RULE:
- case I:a=NTV;
- return(tf(a,a));
- case G_ZERO:return(NTV);
- case HD:a=NTV;
- return(tf(lt(a),a));
- case TL:a=lt(NTV);
- return(tf(a,a));
- case BODY:a=NTV,b=NTV;
- return(tf(ap(a,b),a));
- case LAST:a=NTV,b=NTV;
- return(tf(ap(a,b),b));
- case S_p:a=NTV,b=NTV;
- c=lt(b);
- return(tf3(tf(a,b),tf(a,c),a,c));
- case U:
- case U_: a=NTV,b=NTV;
- c=lt(a);
- return(tf2(tf2(a,c,b),c,b));
- case Uf: a=NTV,b=NTV,c=NTV;
- return(tf2(tf2(tf(a,b),a,c),b,c));
- case COND: a=NTV;
- return(tf3(bool_t,a,a,a));
- case EQ:case GR:case GRE:
- case NEQ: a=NTV;
- return(tf2(a,a,bool_t));
- case NEG: return(tfnum);
- case AND:
- case OR: return(tfbool2);
- case NOT: return(tfbool);
- case MERGE:
- case APPEND: a=lt(NTV);
- return(tf2(a,a,a));
- case STEP: return(tstep);
- case STEPUNTIL: return(tstepuntil);
- case MAP: a=NTV; b=NTV;
- return(tf2(tf(a,b),lt(a),lt(b)));
- case FLATMAP: a=NTV,b=lt(NTV);
- return(tf2(tf(a,b),lt(a),b));
- case FILTER: a=NTV; b=lt(a);
- return(tf2(tf(a,bool_t),b,b));
- case ZIP: a=NTV; b=NTV;
- return(tf2(lt(a),lt(b),lt(pair_t(a,b))));
- case FOLDL: a=NTV; b=NTV;
- return(tf3(tf2(a,b,a),a,lt(b),a));
- case FOLDL1: a=NTV;
- return(tf2(tf2(a,a,a),lt(a),a));
- case LIST_LAST: a=NTV;
- return(tf(lt(a),a));
- case FOLDR: a=NTV; b=NTV;
- return(tf3(tf2(a,b,b),b,lt(a),b));
- case MATCHINT:
- case MATCH: a=NTV,b=NTV;
- return(tf3(a,b,a,b));
- case TRY: a=NTV;
- return(tf2(a,a,a));
- case DROP:
- case TAKE: a=lt(NTV);
- return(tf2(num_t,a,a));
- case SUBSCRIPT:a=NTV;
- return(tf2(num_t,lt(a),a));
- case P: a=NTV;
- b=lt(a);
- return(tf2(a,b,b));
- case B_p: a=NTV,b=NTV;
- c=lt(a);
- return(tf3(a,tf(b,c),b,c));
- case C_p: a=NTV,b=NTV;
- c=lt(b);
- return(tf3(tf(a,b),c,a,c));
- case S1: a=NTV,b=NTV,c=NTV,d=NTV;
- return(tf4(tf2(a,b,c),tf(d,a),tf(d,b),d,c));
- case B1: a=NTV,b=NTV,c=NTV,d=NTV;
- return(tf4(tf(a,b),tf(c,a),tf(d,c),d,b));
- case C1: a=NTV,b=NTV,c=NTV,d=NTV;
- return(tf4(tf2(a,b,c),tf(d,a),b,d,c));
- case SEQ: a=NTV,b=NTV;
- return(tf2(a,b,b));
- case ITERATE1:
- case ITERATE: a=NTV;
- return(tf2(tf(a,a),a,lt(a)));
- case EXEC: { if(!exec_t)
- a=ap2(comma_t,ltchar,ap2(comma_t,num_t,void_t)),
- exec_t=tf(ltchar,ap2(comma_t,ltchar,a));
- return(exec_t); }
- case READBIN:
- case READ: { if(!read_t)
- read_t=tf(char_t,ltchar);
- /* $- is ap(READ,0) */
- return(read_t); }
- case FILESTAT: { if(!filestat_t)
- filestat_t=tf(ltchar,pair_t(pair_t(num_t,num_t),num_t));
- return(filestat_t); }
- case FILEMODE:
- case GETENV:
- case NB_STARTREAD:
- case STARTREADBIN:
- case STARTREAD: return(tfstrstr);
- case GETARGS: return(tf(char_t,lt(ltchar)));
- case SHOWHEX:
- case SHOWOCT:
- case SHOWNUM: return(tf(num_t,ltchar));
- case SHOWFLOAT:
- case SHOWSCALED: return(tf2(num_t,num_t,ltchar));
- case NUMVAL: return(tf(ltchar,num_t));
- case INTEGER: return(tf(num_t,bool_t));
- case CODE: return(tf(char_t,num_t));
- case DECODE: return(tf(num_t,char_t));
- case LENGTH: return(tf(lt(NTV),num_t));
- case ENTIER_FN: case ARCTAN_FN: case EXP_FN: case SIN_FN:
- case COS_FN: case SQRT_FN: case LOG_FN: case LOG10_FN:
- return(tfnumnum);
- case MINUS:case PLUS:case TIMES:case INTDIV:case FDIV:
- case MOD:case POWER: return(tfnum2);
- case True: case False: return(bool_t);
- case NIL: a=lt(NTV);
- return(a);
- case NILS: return(ltchar);
- case MKSTRICT: a=NTV;
- return(tf(char_t,tf(a,a)));
-/* the following are not the true types of the G_fns, which have the action
- Ai->lt(bnf_t)->(B:lt(bnf_t))
- here represented by the type Ai->B. G_CLOSE interfaces the parser fns to
- the outside world */
- case G_ALT: a=NTV;
- return(tf2(a,a,a));
- case G_ERROR: a=NTV;
- return(tf2(a,tf(lt(bnf_t),a),a));
- case G_OPT:
- case G_STAR: a=NTV;
- return(tf(a,lt(a)));
- case G_FBSTAR: a=NTV; b=tf(a,a);
- return(tf(b,b));
- case G_SYMB: return(tfstrstr);
- case G_ANY: return(ltchar);
- case G_SUCHTHAT: return(tf(tf(ltchar,bool_t),ltchar));
- case G_END: return(lt(bnf_t));
- case G_STATE: return(tl[hd[tl[bnf_t]]]);
- case G_SEQ: a=NTV; b=NTV;
- return(tf2(a,tf(a,b),b));
- /* G_RULE has same type as I */
- case G_CLOSE: a=NTV;
- if(col_fn) /* offside rule used */
- if(col_fn== -1) /* arbitrary flag */
- TYPERRS++; /*overkill, see note on checkcolfn*/
- else checkcolfn();
- return(tf3(ltchar,a,lt(bnf_t),a));
- case OFFSIDE: return(ltchar);
- /* pretend, used by indent, see prelude */
- case FAIL: /* compiled from last guard on rhs */
- case CONFERROR:
- case BADCASE:
- case UNDEF: return(NTV);
- case ERROR: return(tf(ltchar,NTV));
- default: printf("do not know type of ");
- out(stdout,x);
- putchar('\n');
- return(wrong_t);
- }
- default: printf("unexpected tag in etype ");
- out(stdout,tag[x]);
- putchar('\n');
- return(wrong_t);
- }
-}
-
-rhs_here(r)
-word r;
-{ if(tag[r]==LABEL)return(hd[r]);
- if(tag[r]==TRIES)return(hd[hd[lastlink(tl[r])]]);
- return(0); /* something wrong */
-} /* efficiency hack, sometimes we set lineptr to rhs, can extract here_info
- as above when needed */
-
-conforms(p,t,e,ngt) /* returns new environment of local type bindings obtained
- by conforming pattern p to type t; -1 means failure */
-word p,t,e,ngt;
-{ if(e==-1)return(-1);
- if(tag[p]==ID&&!isconstructor(p))return(cons(cons(p,t),e));
- if(hd[p]==CONST)
- { unify(etype(tl[p],e,ngt),t); return(e); }
- if(tag[p]==CONS)
- { word at=NTV;
- if(!unify(lt(at),t))return(-1);
- return(conforms(tl[p],t,conforms(hd[p],at,e,ngt),ngt)); }
- if(tag[p]==TCONS)
- { word at=NTV,bt=NTV;
- if(!unify(ap2(comma_t,at,bt),t))return(-1);
- return(conforms(tl[p],bt,conforms(hd[p],at,e,ngt),ngt)); }
- if(tag[p]==PAIR)
- { word at=NTV,bt=NTV;
- if(!unify(ap2(comma_t,at,ap2(comma_t,bt,void_t)),t))return(-1);
- return(conforms(tl[p],bt,conforms(hd[p],at,e,ngt),ngt)); }
- if(tag[p]==AP&&tag[hd[p]]==AP&&hd[hd[p]]==PLUS) /* n+k pattern */
- { if(!unify(num_t,t))return(1);
- return(conforms(tl[p],num_t,e,ngt)); }
-{ word p_args=NIL,pt;
- while(tag[p]==AP)p_args=cons(tl[p],p_args),p=hd[p];
- if(!isconstructor(p))
- { type_error4(p); return(-1); }
- if(id_type(p)==undef_t)
- { type_error5(p); return(-1); }
- pt= /*instantiate(id_type(p)); */
- instantiate(ATNAMES?rep_t(id_type(p),ATNAMES):id_type(p));
- while(p_args!=NIL&&isarrow_t(pt))
- { e=conforms(hd[p_args],tl[hd[pt]],e,ngt),pt=tl[pt],p_args=tl[p_args];
- if(e==-1)return(-1); }
- if(p_args!=NIL||isarrow_t(pt)){ type_error3(p); return(-1); }
- if(!unify(pt,t))return(-1);
- return(e);
-}}
-
-locate(s) /* for locating type errors */
-char *s;
-{ TYPERRS++;
- if(TYPERRS==1||lastloc!=current_id) /* avoid tedious repetition */
- if(current_id)
- if(tag[current_id]==DATAPAIR) /* see checkfbs */
- { locate_inc();
- printf("%s in binding for %s\n",s,(char *)hd[current_id]);
- return; }
- else
- { extern word fnts;
- word x=current_id;
- printf("%s in definition of ",s);
- while(tag[x]==CONS)
- if(tag[tl[x]]==ID&&member(fnts,tl[x]))
- printf("nonterminal "),x=hd[x]; else /*note1*/
- out_formal1(stdout,hd[x]),printf(", subdef of "),
- x=tl[x];
- printf("%s",get_id(x));
- putchar('\n'); }
- else printf("%s in expression\n",s);
- if(lineptr)sayhere(lineptr,0); else
- if(current_id&&id_who(current_id)!=NIL)sayhere(id_who(current_id),0);
- lastloc=current_id;
-}
-/* note1: this is hack to suppress extra `subdef of <fst start symb>' when
- reporting error in defn of non-terminal in %bnf stuff */
-
-sayhere(h,nl) /* h is hereinfo - reports location (in parens, newline if nl)
- and sets errline/errs if not already set */
-word h,nl;
-{ extern word errs,errline;
- extern char *current_script;
- if(tag[h]!=FILEINFO)
- { h=rhs_here(h);
- if(tag[h]!=FILEINFO)
- { fprintf(stderr,"(impossible event in sayhere)\n"); return; }}
- printf("(line %3d of %s\"%s\")",tl[h],
- (char *)hd[h]==current_script?"":"%insert file ",(char *)hd[h]);
- if(nl)putchar('\n'); else putchar(' ');
- if((char *)hd[h]==current_script)
- { if(!errline) /* tells editor where first error is */
- errline=tl[h]; }
- else { if(!errs)errs=h; }
-}
-
-type_error(a,b,t1,t2)
-char *a,*b;
-word t1,t2;
-{ t1=redtvars(ap(subst(t1),subst(t2)));
- t2=tl[t1];t1=hd[t1];
- locate("type error");
- printf("cannot %s ",a);out_type(t1);
- printf(" %s ",b);out_type(t2);putchar('\n');
-}
-
-type_error1(x) /* typename in expression */
-word x;
-{ locate("type error");
- printf("typename used as identifier (%s)\n",get_id(x));
-}
-
-type_error2(x) /* undefined name in expression */
-word x;
-{ if(compiling)return; /* treat as type error only in $+ data */
- TYPERRS++;
- printf("undefined name - %s\n",get_id(x));
-}
-
-type_error3(x) /* constructor used at wrong arity in formal */
-word x;
-{ locate("error");
- printf("constructor \"%s\" used at wrong arity in formal\n", get_id(x));
-}
-
-type_error4(x) /* non-constructor as head of formal */
-word x;
-{ locate("error");
- printf("illegal object \""); out_pattern(stdout,x);
- printf("\" as head of formal\n");
-}
-
-type_error5(x) /* undeclared constructor in formal */
-word x;
-{ locate("error");
- printf("undeclared constructor \""); out_pattern(stdout,x);
- printf("\" in formal\n");
- ND=add1(x,ND);
-}
-
-type_error6(x,f,a)
-word x,f,a;
-{ TYPERRS++;
- printf("incorrect declaration "); sayhere(lineptr,1);
- printf("specified, %s :: ",get_id(x)); out_type(f); putchar('\n');
- printf("inferred, %s :: ",get_id(x)); out_type(redtvars(subst(a)));
- putchar('\n');
-}
-
-type_error7(t,args)
-word t,args;
-{ word i=1;
- while((args=tl[args])!=NIL)i++;
- locate("type error");
- printf(i==1?"1st":i==2?"2nd":i==3?"3rd":"%dth",i);
- printf(" arg of zip has type :: ");
- out_type(redtvars(subst(t)));
- printf("\n - should be list\n");
-}
-
-type_error8(t1,t2)
-word t1,t2;
-{ word big;
- t1=subst(t1); t2=subst(t2);
- if(same(hd[t1],hd[t2]))
- t1=tl[t1],t2=tl[t2]; /* discard `[bnf_t]->' */
- t1=redtvars(ap(t1,t2));
- t2=tl[t1];t1=hd[t1];
- big = size(t1)>=10 || size(t2)>=10;
- locate("type error");
- printf("cannot unify%s ",big?"\n ":"");out_type(t1);
- printf(big?"\nwith\n ":" with ");out_type(t2);putchar('\n');
-}
-
-unify(t1,t2) /* works by side-effecting SUBST, returns 1,0 as it succeeds
- or fails */
-word t1,t2;
-{ t1=subst(t1),t2=subst(t2);
- if(t1==t2)return(1);
- if(isvar_t(t1)&&!occurs(t1,t2))
- { addsubst(t1,t2); return(1); }
- if(isvar_t(t2)&&!occurs(t2,t1))
- { addsubst(t2,t1); return(1); }
- if(iscompound_t(t1)&&iscompound_t(t2)&&
- unify1(hd[t1],hd[t2])&&unify1(tl[t1],tl[t2]))return(1);
- type_error("unify","with",t1,t2);
- return(0);
-}
-
-unify1(t1,t2) /* inner call - exactly like unify, except error reporting is
- done only by top level, see above */
- /* we do this to avoid printing inner parts of types */
-word t1,t2;
-{ t1=subst(t1),t2=subst(t2);
- if(t1==t2)return(1);
- if(isvar_t(t1)&&!occurs(t1,t2))
- { addsubst(t1,t2); return(1); }
- if(isvar_t(t2)&&!occurs(t2,t1))
- { addsubst(t2,t1); return(1); }
- if(iscompound_t(t1)&&iscompound_t(t2))
- return(unify1(hd[t1],hd[t2])&&unify1(tl[t1],tl[t2]));
- return(0);
-}
-
-subsumes(t1,t2) /* like unify but lop-sided; returns 1,0 as t2 falls, doesnt
- fall under t1 */
-word t1,t2;
-{ if(t2==wrong_t)return(1);
- /* special case, shows up only when compiling prelude (changetype etc) */
- return(subsu1(t1,t2,t2)); }
-
-subsu1(t1,t2,T2)
-word t1,t2,T2;
-{ t1=subst(t1);
- if(t1==t2)return(1);
- if(isvar_t(t1)&&!occurs(t1,T2))
- { addsubst(t1,t2); return(1); }
- if(iscompound_t(t1)&&iscompound_t(t2))
- return(subsu1(hd[t1],hd[t2],T2)&&subsu1(tl[t1],tl[t2],T2));
- return(0);
-}
-
-walktype(t,f) /* make a copy of t with f applied to its variables */
-word t;
-word (*f)();
-{ if(isvar_t(t))return((*f)(t));
- if(iscompound_t(t))
- { word h1=walktype(hd[t],f);
- word t1=walktype(tl[t],f);
- return(h1==hd[t]&&t1==tl[t]?t:ap(h1,t1)); }
- return(t);
-}
-
-occurs(tv,t) /* does tv occur in type t? */
-word tv,t;
-{ while(iscompound_t(t))
- { if(occurs(tv,tl[t]))return(1);
- t=hd[t]; }
- return(tv==t);
-}
-
-ispoly(t) /* does t contain tvars? (should call subst first) */
-word t;
-{ while(iscompound_t(t))
- { if(ispoly(tl[t]))return(1);
- t=hd[t]; }
- return(isvar_t(t));
-}
-
-word SUBST[hashsize]; /* hash table of substitutions */
-
-clear_SUBST()
-/* To save time and space we call this after a type inference to clear out
- substitutions in extinct variables. Calling this too often can slow you
- down - whence #define reset_SUBST, see above */
-{ word i;
- fixshows();
- for(i=0;i<hashsize;i++)SUBST[i]=0;
- /*printf("tvcount=%d\n",tvcount); /* probe */
- tvcount=1;
- return(0); /* see defn of reset_SUBST */
-}
-/* doubling hashsize from 512 to 1024 speeded typecheck by only 3% on
- parser.m (=350 line block, used c. 5000 tvars) - may be worth increasing
- for very large programs however. Guesstimate - further increase from
- 512 would be worthwhile on blocks>2000 lines */
-
-fixshows()
-{ while(showchain!=NIL)
- { tl[hd[showchain]]=subst(tl[hd[showchain]]);
- showchain=tl[showchain]; }
-}
-
-lookup(tv) /* find current substitution for type variable */
-word tv;
-{ word h=SUBST[hashval(tv)];
- while(h)
- { if(eqtvar(hd[hd[h]],tv))return(tl[hd[h]]);
- h=tl[h]; }
- return(tv); /* no substitution found, so answer is self */
-}
-
-addsubst(tv,t) /* add new substitution to SUBST */
-word tv,t;
-{ word h=hashval(tv);
- SUBST[h]=cons(cons(tv,t),SUBST[h]);
-}
-
-ult(tv) /* fully substituted out value of a type var */
-word tv;
-{ word s=lookup(tv);
- return(s==tv?tv:subst(s));
-}
-
-subst(t) /* returns fully substituted out value of type expression */
-word t;
-{ return(walktype(t,ult));
-}
-
-word localtvmap=NIL;
-word NGT=0;
-
-lmap(tv)
-word tv;
-{ word l;
- if(non_generic(tv))return(tv);
- for(l=localtvmap;l!=NIL;l=tl[l])
- if(hd[hd[l]]==tv)return(tl[hd[l]]);
- localtvmap=cons(cons(tv,l=NTV),localtvmap);
- return(l);
-}
-
-linst(t,ngt) /* local instantiate */
-word t; /* relevant tvars are those not in ngt */
-{ localtvmap=NIL; NGT=ngt;
- return(walktype(t,lmap));
-}
-
-non_generic(tv)
-word tv;
-{ word x;
- for(x=NGT;x!=NIL;x=tl[x])
- if(occurs(tv,subst(hd[x])))return(1);
- return(0);
-} /* note that when a non-generic tvar is unified against a texp, all tvars
- in texp become non-generic; this is catered for by call to subst above
- (obviating the need for unify to directly side-effect NGT) */
-
-word tvmap=NIL;
-
-mapup(tv)
-word tv;
-{ word *m= &tvmap;
- tv=gettvar(tv);
- while(--tv)m= &tl[*m];
- if(*m==NIL)*m=cons(NTV,NIL);
- return(hd[*m]);
-}
-
-instantiate(t) /* make a copy of t with a new set of type variables */
-word t; /* t MUST be in reduced form - see redtvars */
-{ tvmap=NIL;
- return(walktype(t,mapup));
-}
-
-ap_subst(t,args) /* similar, but with a list of substitions for the type
- variables provided (args). Again, t must be in reduced form */
-word t,args;
-{ word r;
- tvmap=args;
- r=walktype(t,mapup);
- tvmap=NIL; /* ready for next use */
- return(r);
-}
-
-
-mapdown(tv)
-word tv;
-{ word *m= &tvmap;
- word i=1;
- while(*m!=NIL&&!eqtvar(hd[*m],tv))m= &tl[*m],i++;
- if(*m==NIL)*m=cons(tv,NIL);
- return(mktvar(i));
-}
-
-redtvars(t) /* renames the variables in t, in order of appearance to walktype,
- using the numbers 1,2,3... */
-word t;
-{ tvmap=NIL;
- return(walktype(t,mapdown));
-}
-
-
-remove1(e,ss) /* destructively remove e from set with address ss, returning
- 1 if e was present, 0 otherwise */
-word e,*ss;
-{ while(*ss!=NIL&&hd[*ss]<e)ss= &tl[*ss]; /* we assume set in address order */
- if(*ss==NIL||hd[*ss]!=e)return(0);
- *ss=tl[*ss];
- return(1);
-}
-
-setdiff(s1,s2) /* destructive on s1, returns set difference */
-word s1,s2; /* both are in ascending address order */
-{ word *ss1= &s1;
- while(*ss1!=NIL&&s2!=NIL)
- if(hd[*ss1]==hd[s2])*ss1=tl[*ss1]; else /* removes element */
- if(hd[*ss1]<hd[s2])ss1= &tl[*ss1];
- else s2=tl[s2];
- return(s1);
-}
-
-add1(e,s) /* inserts e destructively into set s, kept in ascending address
- order */
-word e,s;
-{ word s1=s;
- if(s==NIL||e<hd[s])return(cons(e,s));
- if(e==hd[s])return(s); /* no duplicates! */
- while(tl[s1]!=NIL&&e>hd[tl[s1]])s1=tl[s1];
- if(tl[s1]==NIL)tl[s1]=cons(e,NIL);else
- if(e!=hd[tl[s1]])tl[s1]=cons(e,tl[s1]);
- return(s);
-}
-
-word NEW; /* nasty hack, see rules */
-
-newadd1(e,s) /* as above, but with side-effect on NEW */
-word e,s;
-{ word s1=s;
- NEW=1;
- if(s==NIL||e<hd[s])return(cons(e,s));
- if(e==hd[s]){ NEW=0; return(s); } /* no duplicates! */
- while(tl[s1]!=NIL&&e>hd[tl[s1]])s1=tl[s1];
- if(tl[s1]==NIL)tl[s1]=cons(e,NIL);else
- if(e!=hd[tl[s1]])tl[s1]=cons(e,tl[s1]);
- else NEW=0;
- return(s);
-}
-
-UNION(s1,s2) /* destructive on s1; s1, s2 both in address order */
-word s1,s2;
-{ word *ss= &s1;
- while(*ss!=NIL&&s2!=NIL)
- if(hd[*ss]==hd[s2])ss= &tl[*ss],s2=tl[s2]; else
- if(hd[*ss]<hd[s2])ss= &tl[*ss];
- else *ss=cons(hd[s2],*ss),ss= &tl[*ss],s2=tl[s2];
- if(*ss==NIL)
- while(s2!=NIL)*ss=cons(hd[s2],*ss),ss= &tl[*ss],s2=tl[s2];
- /* must copy tail of s2, in case of later destructive operations on s1 */
- return(s1);
-}
-
-intersection(s1,s2) /* s1, s2 and result all in address order */
-word s1,s2;
-{ word r=NIL;
- while(s1!=NIL&&s2!=NIL)
- if(hd[s1]==hd[s2])r=cons(hd[s1],r),s1=tl[s1],s2=tl[s2]; else
- if(hd[s1]<hd[s2])s1=tl[s1];
- else s2=tl[s2];
- return(reverse(r));
-}
-
-deps(x) /* returns list of the free identifiers in expression x */
-word x;
-{ word d=NIL;
-L:switch(tag[x])
-{ case AP:
- case TCONS:
- case PAIR:
- case CONS: d=UNION(d,deps(hd[x]));
- x=tl[x];
- goto L;
- case ID: return(isconstructor(x)?d:add1(x,d));
- case LAMBDA: /* d=UNION(d,patdeps(hd[x]));
- /* should add this - see sahbug3.m */
- return(rembvars(UNION(d,deps(tl[x])),hd[x]));
- case LET: d=rembvars(UNION(d,deps(tl[x])),dlhs(hd[x]));
- return(UNION(d,deps(dval(hd[x]))));
- case LETREC: { word y;
- d=UNION(d,deps(tl[x]));
- for(y=hd[x];y!=NIL;y=tl[y])
- d=UNION(d,deps(dval(hd[y])));
- for(y=hd[x];y!=NIL;y=tl[y])
- d=rembvars(d,dlhs(hd[y]));
- return(d); }
- case LEXER: while(x!=NIL)
- d=UNION(d,deps(tl[tl[hd[x]]])),
- x=tl[x];
- return(d);
- case TRIES:
- case LABEL: x=tl[x]; goto L;
- case SHARE: x=hd[x]; goto L; /* repeated analysis - fix later */
- default: return(d);
-}}
-
-rembvars(x,p) /* x is list of ids in address order, remove bv's of pattern p
- (destructive on x) */
-word x,p;
-{ L:
- switch(tag[p])
- { case ID: return(remove1(p,&x),x);
- case CONS: if(hd[p]==CONST)return(x);
- x=rembvars(x,hd[p]);p=tl[p];goto L;
- case AP: if(tag[hd[p]]==AP&&hd[hd[p]]==PLUS)
- p=tl[p]; /* for n+k patterns */
- else { x=rembvars(x,hd[p]);p=tl[p]; }
- goto L;
- case PAIR:
- case TCONS: x=rembvars(x,hd[p]);p=tl[p];goto L;
- default: fprintf(stderr, "impossible event in rembvars\n");
- return(x);
-}}
-
-member(s,x)
-word s,x;
-{ while(s!=NIL&&x!=hd[s])s=tl[s];
- return(s!=NIL);
-}
-
-printgraph(title,g) /* for debugging info */
-char *title;
-word g;
-{ printf("%s\n",title);
- while(g!=NIL)
- { printelement(hd[hd[g]]); putchar(':');
- printelement(tl[hd[g]]); printf(";\n");
- g=tl[g]; }
-}
-
-printelement(x)
-word x;
-{ if(tag[x]!=CONS){ out(stdout,x); return; }
- putchar('(');
- while(x!=NIL)
- { out(stdout,hd[x]);
- x=tl[x];
- if(x!=NIL)putchar(' '); }
- putchar(')');
-}
-
-printlist(title,l) /* for debugging */
-char *title;
-word l;
-{ printf("%s",title);
- while(l!=NIL)
- { printelement(hd[l]);
- l=tl[l];
- if(l!=NIL)putchar(','); }
- printf(";\n");
-}
-
-printob(title,x) /* for debugging */
-char *title;
-word x;
-{ printf("%s",title); out(stdout,x); putchar('\n');
- return(x); }
-
-print2obs(title,title2,x,y) /* for debugging */
-char *title,*title2;
-word x,y;
-{ printf("%s",title); out(stdout,x); printf("%s",title2); out(stdout,y); putchar('\n');
-}
-
-word allchars=0; /* flag used by tail */
-
-out_formal1(f,x)
-FILE *f;
-word x;
-{ extern word nill;
- if(hd[x]==CONST)x=tl[x];
- if(x==NIL)fprintf(f,"[]"); else
- if(tag[x]==CONS&&tail(x)==NIL)
- if(allchars)
- { fprintf(f,"\"");while(x!=NIL)fprintf(f,"%s",charname(hd[x])),x=tl[x];
- fprintf(f,"\""); } else
- { fprintf(f,"[");
- while(x!=nill&&x!=NIL)
- { out_pattern(f,hd[x]);
- x=tl[x];
- if(x!=nill&&x!=NIL)fprintf(f,","); }
- fprintf(f,"]"); } else
- if(tag[x]==AP||tag[x]==CONS)
- { fprintf(f,"("); out_pattern(f,x);
- fprintf(f,")"); } else
- if(tag[x]==TCONS||tag[x]==PAIR)
- { fprintf(f,"(");
- while(tag[x]==TCONS)
- { out_pattern(f,hd[x]);
- x=tl[x]; fprintf(f,","); }
- out_pattern(f,hd[x]); fprintf(f,","); out_pattern(f,tl[x]);
- fprintf(f,")"); } else
- if(tag[x]==INT&&neg(x)||tag[x]==DOUBLE&&get_dbl(x)<0)
- { fprintf(f,"("); out(f,x); fprintf(f,")"); } /* -ve numbers */
- else
- out(f,x); /* all other cases */
-}
-
-out_pattern(f,x)
-FILE *f;
-word x;
-{ if(tag[x]==CONS)
- if(hd[x]==CONST&&(tag[tl[x]]==INT||tag[tl[x]]==DOUBLE))out(f,tl[x]); else
- if(hd[x]!=CONST&&tail(x)!=NIL)
- { out_formal(f,hd[x]); fprintf(f,":"); out_pattern(f,tl[x]); }
- else out_formal(f,x);
- else out_formal(f,x);
-}
-
-out_formal(f,x)
-FILE *f;
-word x;
-{ if(tag[x]!=AP)
- out_formal1(f,x); else
- if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- { out_formal(f,tl[x]); fprintf(f,"+"); out(f,tl[hd[x]]); }
- else
- { out_formal(f,hd[x]); fprintf(f," "); out_formal1(f,tl[x]); }
-}
-
-tail(x)
-word x;
-{ allchars=1;
- while(tag[x]==CONS)allchars&=(is_char(hd[x])),x=tl[x];
- return(x);
-}
-
-out_type(t) /* for printing external representation of types */
-word t;
-{ while(isarrow_t(t))
- { out_type1(tl[hd[t]]);
- printf("->");
- t=tl[t]; }
- out_type1(t);
-}
-
-out_type1(t)
-word t;
-{ if(iscompound_t(t)&&!iscomma_t(t)&&!islist_t(t)&&!isarrow_t(t))
- { out_type1(hd[t]);
- putchar(' ');
- t=tl[t]; }
- out_type2(t);
-}
-
-out_type2(t)
-word t;
-{ if(islist_t(t))
- { putchar('[');
- out_type(tl[t]); /* could be out_typel, but absence of parentheses
- might be confusing */
- putchar(']'); }else
- if(iscompound_t(t))
- { putchar('(');
- out_typel(t);
- if(iscomma_t(t)&&tl[t]==void_t)putchar(',');
- /* type of a one-tuple -- an anomaly that should never occur */
- putchar(')'); }else
- switch(t)
- {
- case bool_t: printf("bool"); return;
- case num_t: printf("num"); return;
- case char_t: printf("char"); return;
- case wrong_t: printf("WRONG"); return;
- case undef_t: printf("UNKNOWN"); return;
- case void_t: printf("()"); return;
- case type_t: printf("type"); return;
- default: if(tag[t]==ID)printf("%s",get_id(t));else
- if(isvar_t(t))
- { word n=gettvar(t);
- /*if(1)printf("t%d",n-1); else /* experiment, suppressed */
- /*if(n<=26)putchar('a'+n-1); else /* experiment */
- if(n>0&&n<7)while(n--)putchar('*'); /* 6 stars max */
- else printf("%d",n); }else
- if(tag[t]==STRCONS) /* pname - see hack in privatise */
- { extern char *current_script;
- if(tag[pn_val(t)]==ID)printf("%s",get_id(pn_val(t))); else
- /* ?? one level of indirection sometimes present */
- if(strcmp((char *)hd[tl[t_info(t)]],current_script)==0)
- printf("%s",(char *)hd[hd[t_info(t)]]); else /* elision */
- printf("`%s@%s'",
- (char *)hd[hd[t_info(t)]], /* original typename */
- (char *)hd[tl[t_info(t)]]); /* sourcefile */ }
- else printf("<BADLY FORMED TYPE:%d,%d,%d>",tag[t],hd[t],tl[t]);
- }
-}
-
-out_typel(t)
-word t;
-{ while(iscomma_t(t))
- { out_type(tl[hd[t]]);
- t=tl[t];
- if(iscomma_t(t))putchar(',');
- else if(t!=void_t)printf("<>"); } /* "tuple-cons", shouldn't occur free */
- if(t==void_t)return;
- out_type(t);
-}
-
-/* end of MIRANDA TYPECHECKER */
-