diff options
Diffstat (limited to 'data.c')
-rw-r--r-- | data.c | 1315 |
1 files changed, 1315 insertions, 0 deletions
@@ -0,0 +1,1315 @@ +/* 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. * + * * + * Revised to C11 standard and made 64bit compatible, January 2020 * + *------------------------------------------------------------------------*/ + +#include "data.h" +#include "big.h" +#include "lex.h" +#define INITSPACE 1250000 +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 int atgc,loading; /* flags, set in steer.c */ + +word *dstack=0,*stackp,*dlim; +/* stackp=dstack; /* if load_script made interruptible, add to reset */ + +#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 */ + +static void bases(void); +static void bindparams(word,word); +static void dsetup(void); +static void dump_defs(word,FILE *); +static void dump_ob(word,FILE *); +static word hdsort(word); +static word load_defs(FILE *); +static void mark(word); +static void unscramble(word); + +word trueheapsize() +{ return(nogcs==0?listp-ATOMLIMIT+1:SPACE); } + +void 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"); +} + +void 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 */ +} + +void mallocfail(x) +char *x; +{ fprintf(stderr,"panic: cannot find enough free space for %s\n",x); + exit(1); +} + +void resetgcstats() +{ cellcount= -claims; + nogcs = 0; + initclock(); +} + +word make(t,x,y) /* creates a new cell with "tag" t, "hd" x and "tl" y */ +unsigned char t; word 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 %ld to %ld>>\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 */ + +void setwd(x,a,b) +word x,a,b; +{ hd[x]= a; + tl[x]= b; } + +int collecting=0; /* flag for reset(), in case interrupt strikes in gc */ + +void 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 int 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 = %ld\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) */ + bases(); +/*if(atgc)printf("bases() done\n"); /* DEBUG */ + listp= ATOMLIMIT - 1; + cellcount+= claims; + claims= 0; + collecting=0; +} +/* int Icount; /* DEBUG */ + +void 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 */ +} + +void 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 *pnvec,nextpn; /* 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 */ +} + +void 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; } +} + +/* test added Jan 2020 - DT */ +#define wordsize (__WORDSIZE) +#if wordsize==32 +#define splitdouble +union fpdatum {double real; struct{word left;word right;} bits;}; +#elif wordsize==64 +union fpdatum {double real; word bits;}; +#else +#error "platform has unknown word size" +#endif + +double get_dbl(x) +word x; +{ union fpdatum r; +#ifdef splitdouble + r.bits.left= hd[x]; + r.bits.right= tl[x]; +#else + r.bits= hd[x]; +#endif + 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 isfinite() */ + +word sto_dbl(R) +double R; +{ union fpdatum r; +#if !defined sparc /* */ + if(!isfinite(R))fpe_error(); /* see note on arithmetic model above */ +#endif + r.real=R; +#ifdef splitdouble + return(make(DOUBLE,r.bits.left,r.bits.right)); +#else + return(make(DOUBLE,r.bits,0)); +#endif +} + +void setdbl(x,R) +word x; +double R; +{ union fpdatum r; +#if !defined sparc /* */ + if(!isfinite(R))fpe_error(); /* see note on arithmetic model above */ +#endif + r.real=R; + tag[x]=DOUBLE; +#ifdef splitdouble + hd[x]=r.bits.left; tl[x]=r.bits.right; +#else + hd[x]=r.bits; tl[x]=0; +#endif +} + +word sto_char(c) /* assumes 0<=c<=UMAX */ +int c; +{ return c<256?c:make(UNICODE,c,0); } + +word 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); +} + +int is_char(x) +word x; +{ return 0<=x && x<256 || tag[x]==UNICODE; } + +word 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 + w means (sizeof(word)) in bytes + + (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 <w bytes> + + complete script __WORDSIZE + 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 __WORDSIZE + XVERSION + '\1' + <w bytes> (=errline) + ... (rest as normal script) + + syntax-error script __WORDSIZE + XVERSION + `\0' + <w 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 +#error "coding scheme breaks down: XLIMIT>512" +#endif + +void putword(x,f) +word x; +FILE *f; +{ int i=sizeof(word); + putc(x&255,f); + while(--i)x>>=8,putc(x&255,f); +} + +word getword(f) +FILE *f; +{ int s=0, i=sizeof(word); + word x=getc(f); + while(--i)s += 8, x |= getc(f)<<s; + return x; +} + +void putint(int n,FILE *f) +{ fwrite(&n,sizeof(int),1,f); } + +int getint(FILE *f) +{ int r; + fread(&r,sizeof(int),1,f); + return r; } + +void putdbl(word x,FILE *f) +{ double d = get_dbl(x); + fwrite(&d,sizeof(double),1,f); } + +word getdbl(FILE *f) +{ double d; + fread(&d,sizeof(double),1,f); + return sto_dbl(d); +} + +static char prefix[pnlim]; +word preflen; + +void 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; + +void 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(wordsize,f); + putc(XVERSION,f); /* identifies dump format */ + if(files==NIL){ /* source contains syntax or metatype error */ + extern word oldfiles; + word x; + putc(0,f); + putword(errline,f); + for(x=oldfiles;x!=NIL;x=tl[x]) + fprintf(f,"%s",mkrel(get_fil(hd[x]))),putc(0,f), + /*filename*/ + putword(fil_time(hd[x]),f); /* mtime */ + return; } + if(ND!=NIL)putc(1,f),putword(errline,f); + for(;files!=NIL;files=tl[files]) + { fprintf(f,"%s",mkrel(CFN=get_fil(hd[files]))); /* filename */ + putc(0,f); + putword(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); +} + +void 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), + putint(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 */ +} + +void 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: { 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); + putint(d,f); + x=rest(x); + while(x) + putint(digit(x),f),x=rest(x); + putint(-1,f); + return; } + /* 4 bytes per digit wasteful at current value of IBASE */ + case DOUBLE: putc(DBL_X,f); + putdbl(x,f); +/* + putword(hd[x],f); +#ifdef splitdouble + putword(tl[x],f); +#endif +*/ + return; + case UNICODE: putc(UNICODE_X,f); + putint(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 %ld 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), + putint(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; + +word 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)!= wordsize || 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=getword(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=getword(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=getword(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=getword(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; + +void 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); +} + +void 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]]); +} + +word get_here(x) /* here info for id x */ +word x; +{ word y=id_who(x); + return(tag[y]==CONS?tl[y]:y); +} + +void dsetup() +{ if(!dstack) + { dstack=(word *)malloc(1000*sizeof(word)); + if(dstack==NULL)mallocfail("dstack"); + dlim=dstack+1000; } + stackp=dstack; +} + +void 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 */ +} + +word 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 = getint(f); + *stackp++ = make(INT,ch,0); + x = &rest(stackp[-1]); + ch = getint(f); + while(ch!= -1) + *x=make(INT,ch,0),ch=getint(f),x= &rest(*x); + continue; } + case DBL_X: *stackp++ = getdbl(f); +/* +#ifdef splitdouble + *stackp++ = make(DOUBLE,ch,getword(f)); +#else + *stackp++ = make(DOUBLE,ch,0); +#endif +*/ + continue; + case UNICODE_X: *stackp++ = make(UNICODE,getint(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+getint(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; + +int 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); +} + +word geterrlin(t) /* returns errline from dump of t if relevant, 0 otherwise */ +char *t; +{ char obf[120]; + extern char *dicp,*dicq; + int ch; word 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=getword(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=getword(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); +} + +word 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)); +} + +word 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,"\\%ld",c); + else s[0]=c,s[1]='\0'; + return(s); + } +} + +void 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,"<%ld>",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 */ + +void out1(f,x) +FILE *f; +word x; +{ if(x<0||x>TOP){ fprintf(f,"<%ld>",x); return; } + if(tag[x]==AP) + { out1(f,hd[x]); + putc(' ',f); + out2(f,tl[x]); } + else out2(f,x); } + +void out2(f,x) +FILE *f; +word x; +{ extern char *yysterm[], *cmbnms[]; + if(x<0||x>TOP){ fprintf(f,"<%ld>",x); return; } + if(tag[x]==INT) + { if(rest(x)) + { x=bigtostr(x); + while(x)putc(hd[x],f),x=tl[x]; } + else fprintf(f,"%ld",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,"'\%lx'",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,%ld)",(char *)hd[x],tl[x]); + return; } + if(tag[x]==FILEINFO) + { fprintf(f,"FILEINFO(%s,%ld)",(char *)hd[x],tl[x]); + return; } + if(tag[x]==CONSTRUCTOR) + { fprintf(f,"CONSTRUCTOR(%ld)",hd[x]); + return; } + if(tag[x]==STRCONS) + { fprintf(f,"<$%ld>",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,"<%ld|tag=%d>",x,tag[x]); return; } + putc('(',f); + out(f,x); + putc(')',f); } + +void 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 */ + |