1 /* -*- mode: hugs-c; -*- */
2 /* --------------------------------------------------------------------------
3 * Primitives for manipulating global data structures
5 * Copyright (c) The University of Nottingham and Yale University, 1994-1997.
6 * All rights reserved. See NOTICE for details and conditions of use etc...
7 * Hugs version 1.4, December 1997
9 * $RCSfile: storage.c,v $
11 * $Date: 1998/12/02 13:22:41 $
12 * ------------------------------------------------------------------------*/
19 #include "link.h" /* for nameCons */
22 #include "machdep.h" /* gc-related functions */
24 /*#define DEBUG_SHOWUSE*/
26 /* --------------------------------------------------------------------------
27 * local function prototypes:
28 * ------------------------------------------------------------------------*/
30 static Int local hash Args((String));
31 static Int local saveText Args((Text));
32 static Module local findQualifier Args((Text));
33 static Void local hashTycon Args((Tycon));
34 static List local insertTycon Args((Tycon,List));
35 static Void local hashName Args((Name));
36 static List local insertName Args((Name,List));
37 static Void local patternError Args((String));
38 static Bool local stringMatch Args((String,String));
39 static Bool local typeInvolves Args((Type,Type));
40 static Cell local markCell Args((Cell));
41 static Void local markSnd Args((Cell));
42 static Cell local lowLevelLastIn Args((Cell));
43 static Cell local lowLevelLastOut Args((Cell));
44 static Module local moduleOfScript Args((Script));
45 static Script local scriptThisFile Args((Text));
48 /* --------------------------------------------------------------------------
51 * provides storage for the characters making up identifier and symbol
52 * names, string literals, character constants etc...
54 * All character strings are stored in a large character array, with textHw
55 * pointing to the next free position. Lookup in the array is improved using
56 * a hash table. Internally, text strings are represented by integer offsets
57 * from the beginning of the array to the string in question.
59 * Where memory permits, the use of multiple hashtables gives a significant
60 * increase in performance, particularly when large source files are used.
62 * Each string in the array is terminated by a zero byte. No string is
63 * stored more than once, so that it is safe to test equality of strings by
64 * comparing the corresponding offsets.
66 * Special text values (beyond the range of the text array table) are used
67 * to generate unique `new variable names' as required.
69 * The same text storage is also used to hold text values stored in a saved
70 * expression. This grows downwards from the top of the text table (and is
71 * not included in the hash table).
72 * ------------------------------------------------------------------------*/
74 #define TEXTHSZ 512 /* Size of Text hash table */
75 #define NOTEXT ((Text)(~0)) /* Empty bucket in Text hash table */
76 static Text textHw; /* Next unused position */
77 static Text savedText = NUM_TEXT; /* Start of saved portion of text */
78 static Text nextNewText; /* Next new text value */
79 static Text nextNewDText; /* Next new dict text value */
80 static char DEFTABLE(text,NUM_TEXT);/* Storage of character strings */
81 static Text textHash[TEXTHSZ][NUM_TEXTH]; /* Hash table storage */
83 String textToStr(t) /* find string corresp to given Text*/
85 static char newVar[16];
87 if (0<=t && t<NUM_TEXT) /* standard char string */
90 sprintf(newVar,"d%d",-t); /* dictionary variable */
92 sprintf(newVar,"v%d",t-NUM_TEXT); /* normal variable */
96 String identToStr(v) /*find string corresp to given ident or qualified name*/
98 static char newVar[33];
105 case CONOPCELL : return text+textOf(v);
107 case QUALIDENT : sprintf(newVar,"%s.%s",
108 text+qmodOf(v),text+qtextOf(v));
111 internal("identToStr 2");
114 Syntax identSyntax(v) /* find syntax of ident or qualified ident */
121 case CONOPCELL : return syntaxOf(textOf(v));
123 case QUALIDENT : return syntaxOf(qtextOf(v));
125 internal("identSyntax 2");
128 Text inventText() { /* return new unused variable name */
129 return nextNewText++;
132 Text inventDictText() { /* return new unused dictvar name */
133 return nextNewDText--;
136 Bool inventedText(t) /* Signal TRUE if text has been */
137 Text t; { /* generated internally */
138 return (t<0 || t>=NUM_TEXT);
141 static Int local hash(s) /* Simple hash function on strings */
145 for (v=((int)(*s))*8; *s; s++)
146 v += ((int)(*s))*(j++);
152 Text findText(s) /* Locate string in Text array */
156 Text textPos = textHash[h][hashno];
158 #define TryMatch { Text originalTextPos = textPos; \
160 for (t=s; *t==text[textPos]; textPos++,t++) \
162 return originalTextPos; \
164 #define Skip while (text[textPos++]) ;
166 while (textPos!=NOTEXT) {
168 if (++hashno<NUM_TEXTH) /* look in next hashtable entry */
169 textPos = textHash[h][hashno];
172 while (textPos < textHw) {
183 textPos = textHw; /* if not found, save in array */
184 if (textHw + (Int)strlen(s) + 1 > savedText) {
185 ERRMSG(0) "Character string storage space exhausted"
188 while ((text[textHw++] = *s++) != 0) {
190 if (hashno<NUM_TEXTH) { /* updating hash table as necessary */
191 textHash[h][hashno] = textPos;
192 if (hashno<NUM_TEXTH-1)
193 textHash[h][hashno+1] = NOTEXT;
199 static Int local saveText(t) /* Save text value in buffer */
200 Text t; { /* at top of text table */
201 String s = textToStr(t);
204 if (textHw + l + 1 > savedText) {
205 ERRMSG(0) "Character string storage space exhausted"
209 strcpy(text+savedText,s);
213 /* --------------------------------------------------------------------------
216 * Operator declarations are stored in a table which associates Text values
217 * with Syntax values.
218 * ------------------------------------------------------------------------*/
220 static Int syntaxHw; /* next unused syntax table entry */
221 static struct strSyntax { /* table of Text <-> Syntax values */
224 } DEFTABLE(tabSyntax,NUM_SYNTAX);
226 Syntax defaultSyntax(t) /* Find default syntax of var named */
227 Text t; { /* by t ... */
228 String s = textToStr(t);
229 return isIn(s[0],SYMBOL) ? DEF_OPSYNTAX : APPLIC;
232 Syntax syntaxOf(t) /* look up syntax of operator symbol*/
236 for (i=0; i<syntaxHw; ++i)
237 if (tabSyntax[i].text==t)
238 return tabSyntax[i].syntax;
239 return defaultSyntax(t);
242 Void addSyntax(line,t,sy) /* add (t,sy) to syntax table */
248 for (i=0; i<syntaxHw; ++i)
249 if (tabSyntax[i].text==t) {
250 /* There's no problem with multiple identical fixity declarations.
251 * - but note that it's not allowed by the Haskell report. ADR
253 if (tabSyntax[i].syntax == sy) return;
254 ERRMSG(line) "Attempt to redefine syntax of operator \"%s\"",
259 if (syntaxHw>=NUM_SYNTAX) {
260 ERRMSG(line) "Too many fixity declarations"
264 tabSyntax[syntaxHw].text = t;
265 tabSyntax[syntaxHw].syntax = sy;
269 /* --------------------------------------------------------------------------
272 * Currently, the only attributes that we store for each Ext value is the
273 * corresponding Text label. At some later stage, we may decide to cache
274 * types, predicates, etc. here as a space saving gesture. Given that Text
275 * comparison is cheap, and that this is an experimental implementation, we
276 * will use a straightforward linear search to locate Ext values from their
277 * corresponding Text labels; a hashing scheme can be introduced later if
278 * this turns out to be a problem.
279 * ------------------------------------------------------------------------*/
282 Text DEFTABLE(tabExt,NUM_EXT); /* Storage for Ext names */
285 Ext mkExt(t) /* Allocate or find an Ext value */
291 if (extHw-EXTMIN >= NUM_EXT) {
292 ERRMSG(0) "Ext storage space exhausted"
300 /* --------------------------------------------------------------------------
303 * A Tycon represents a user defined type constructor. Tycons are indexed
304 * by Text values ... a very simple hash function is used to improve lookup
305 * times. Tycon entries with the same hash code are chained together, with
306 * the most recent entry at the front of the list.
307 * ------------------------------------------------------------------------*/
309 #define TYCONHSZ 256 /* Size of Tycon hash table*/
310 #define tHash(x) ((x)%TYCONHSZ) /* Tycon hash function */
311 static Tycon tyconHw; /* next unused Tycon */
312 static Tycon DEFTABLE(tyconHash,TYCONHSZ); /* Hash table storage */
313 struct strTycon DEFTABLE(tabTycon,NUM_TYCON); /* Tycon storage */
315 Tycon newTycon(t) /* add new tycon to tycon table */
319 if (tyconHw-TYCMIN >= NUM_TYCON) {
320 ERRMSG(0) "Type constructor storage space exhausted"
323 tycon(tyconHw).text = t; /* clear new tycon record */
324 tycon(tyconHw).kind = NIL;
325 tycon(tyconHw).defn = NIL;
326 tycon(tyconHw).what = NIL;
327 tycon(tyconHw).conToTag = NIL;
328 tycon(tyconHw).tagToCon = NIL;
329 tycon(tyconHw).mod = currentModule;
330 module(currentModule).tycons = cons(tyconHw,module(currentModule).tycons);
331 tycon(tyconHw).nextTyconHash = tyconHash[h];
332 tyconHash[h] = tyconHw;
337 Tycon findTycon(t) /* locate Tycon in tycon table */
339 Tycon tc = tyconHash[tHash(t)];
341 while (nonNull(tc) && tycon(tc).text!=t)
342 tc = tycon(tc).nextTyconHash;
346 Tycon addTycon(tc) /* Insert Tycon in tycon table - if no clash is caused */
348 Tycon oldtc = findTycon(tycon(tc).text);
351 module(currentModule).tycons=cons(tc,module(currentModule).tycons);
357 static Void local hashTycon(tc) /* Insert Tycon into hash table */
359 Text t = tycon(tc).text;
361 tycon(tc).nextTyconHash = tyconHash[h];
365 Tycon findQualTycon(id) /*locate (possibly qualified) Tycon in tycon table */
371 return findTycon(textOf(id));
373 Text t = qtextOf(id);
374 Module m = findQualifier(qmodOf(id));
378 if (m==currentModule) {
379 /* The Haskell report (rightly) forbids this.
380 * We added it to let the Prelude refer to itself
381 * without having to import itself.
385 for(es=module(m).exports; nonNull(es); es=tl(es)) {
387 if (isPair(e) && isTycon(fst(e)) && tycon(fst(e)).text==t)
392 default : internal("findQualTycon2");
396 Tycon addPrimTycon(t,kind,ar,what,defn) /* add new primitive type constr */
402 Tycon tc = newTycon(t);
404 tycon(tc).kind = kind;
405 tycon(tc).what = what;
406 tycon(tc).defn = defn;
407 tycon(tc).arity = ar;
411 static List local insertTycon(tc,ts) /* insert tycon tc into sorted list*/
416 String s = textToStr(tycon(tc).text);
418 while (nonNull(curr) && strCompare(s,textToStr(tycon(hd(curr)).text))>=0) {
419 if (hd(curr)==tc) /* just in case we get duplicates! */
425 tl(prev) = cons(tc,curr);
429 return cons(tc,curr);
432 List addTyconsMatching(pat,ts) /* Add tycons matching pattern pat */
433 String pat; /* to list of Tycons ts */
434 List ts; { /* Null pattern matches every tycon*/
435 Tycon tc; /* (Tycons with NIL kind excluded) */
436 for (tc=TYCMIN; tc<tyconHw; ++tc)
437 if (!pat || stringMatch(pat,textToStr(tycon(tc).text)))
438 if (nonNull(tycon(tc).kind))
439 ts = insertTycon(tc,ts);
443 /* --------------------------------------------------------------------------
446 * A Name represents a top level binding of a value to an identifier.
447 * Such values may be a constructor function, a member function in a
448 * class, a user-defined or primitive value/function.
450 * Names are indexed by Text values ... a very simple hash functions speeds
451 * access to the table of Names and Name entries with the same hash value
452 * are chained together, with the most recent entry at the front of the
454 * ------------------------------------------------------------------------*/
456 #define NAMEHSZ 256 /* Size of Name hash table */
457 #define nHash(x) ((x)%NAMEHSZ) /* hash fn :: Text->Int */
458 /*static*/Name nameHw; /* next unused name */
459 static Name DEFTABLE(nameHash,NAMEHSZ); /* Hash table storage */
460 struct strName DEFTABLE(tabName,NUM_NAME); /* Name table storage */
462 Name newName(t) /* add new name to name table */
464 if (nameHw-NAMEMIN >= NUM_NAME) {
465 ERRMSG(0) "Name storage space exhausted"
468 name(nameHw).text = t; /* clear new name record */
469 name(nameHw).line = 0;
470 name(nameHw).arity = 0;
471 name(nameHw).number = EXECNAME;
472 name(nameHw).defn = NIL;
473 name(nameHw).stgVar = NIL;
474 name(nameHw).type = NIL;
475 name(nameHw).primop = 0;
476 name(nameHw).mod = currentModule;
478 module(currentModule).names=cons(nameHw,module(currentModule).names);
482 Name findName(t) /* locate name in name table */
484 Name n = nameHash[nHash(t)];
486 while (nonNull(n) && name(n).text!=t) {
487 n = name(n).nextNameHash;
489 assert(isNull(n) || (isName(n) && n < nameHw));
493 Name addName(nm) /* Insert Name in name table - if no clash is caused */
495 Name oldnm = findName(name(nm).text);
498 module(currentModule).names=cons(nm,module(currentModule).names);
505 static Void local hashName(nm) /* Insert Name into hash table */
507 Text t = name(nm).text;
509 name(nm).nextNameHash = nameHash[h];
513 Name findQualName(line,id) /* locate (possibly qualified) name in name table */
522 return findName(textOf(id));
524 Text t = qtextOf(id);
525 Module m = findQualifier(qmodOf(id));
527 if (isNull(m)) return NIL;
528 if (m==currentModule) {
529 /* The Haskell report (rightly) forbids this.
530 * We added it to let the Prelude refer to itself
531 * without having to import itself.
535 for(es=module(m).exports; nonNull(es); es=tl(es)) {
537 if (isName(e) && name(e).text==t)
539 else if (isPair(e) && DOTDOT==snd(e)) {
540 List subentities = NIL;
543 && (tycon(c).what == DATATYPE
544 || tycon(c).what == NEWTYPE))
545 subentities = tycon(c).defn;
547 subentities = cclass(c).members;
548 for(; nonNull(subentities); subentities=tl(subentities)) {
549 assert(isName(hd(subentities)));
550 if (name(hd(subentities)).text == t)
551 return hd(subentities);
557 default : internal("findQualName2");
561 /* --------------------------------------------------------------------------
562 * Primitive functions:
563 * ------------------------------------------------------------------------*/
565 Name addPrimCfun(t,arity,no,rep) /* add primitive constructor func */
569 Int rep; { /* Really AsmRep */
571 name(n).arity = arity;
572 name(n).number = cfunNo(no);
574 name(n).primop = (void*)rep;
578 Int sfunPos(s,c) /* Find position of field with */
579 Name s; /* selector s in constructor c. */
583 for (; nonNull(cns); cns=tl(cns)) {
585 return intOf(snd(hd(cns)));
588 return 0;/*NOTREACHED*/
591 static List local insertName(nm,ns) /* insert name nm into sorted list */
596 String s = textToStr(name(nm).text);
598 while (nonNull(curr) && strCompare(s,textToStr(name(hd(curr)).text))>=0) {
599 if (hd(curr)==nm) /* just in case we get duplicates! */
605 tl(prev) = cons(nm,curr);
609 return cons(nm,curr);
612 List addNamesMatching(pat,ns) /* Add names matching pattern pat */
613 String pat; /* to list of names ns */
614 List ns; { /* Null pattern matches every name */
615 Name nm; /* (Names with NIL type, or hidden */
616 for (nm=NAMEMIN; nm<nameHw; ++nm) /* or invented names are excluded) */
617 if (!inventedText(name(nm).text) && nonNull(name(nm).type)) {
618 String str = textToStr(name(nm).text);
619 if (str[0]!='_' && (!pat || stringMatch(pat,str)))
620 ns = insertName(nm,ns);
625 /* --------------------------------------------------------------------------
626 * A simple string matching routine
627 * `*' matches any sequence of zero or more characters
628 * `?' matches any single character exactly
629 * `@str' matches the string str exactly (ignoring any special chars)
630 * `\c' matches the character c only (ignoring special chars)
631 * c matches the character c only
632 * ------------------------------------------------------------------------*/
634 static Void local patternError(s) /* report error in pattern */
636 ERRMSG(0) "%s in pattern", s
640 static Bool local stringMatch(pat,str) /* match string against pattern */
646 case '\0' : return (*str=='\0');
649 if (stringMatch(pat+1,str))
654 case '?' : if (*str++=='\0')
659 case '[' : { Bool found = FALSE;
660 while (*++pat!='\0' && *pat!=']')
661 if (!found && ( pat[0] == *str ||
670 patternError("missing `]'");
678 case '\\' : if (*++pat == '\0')
679 patternError("extra trailing `\\'");
681 default : if (*pat++ != *str++)
687 /* --------------------------------------------------------------------------
688 * Storage of type classes, instances etc...:
689 * ------------------------------------------------------------------------*/
691 static Class classHw; /* next unused class */
692 static List classes; /* list of classes in current scope */
693 static Inst instHw; /* next unused instance record */
695 static Int dictHw; /* next unused dictionary number */
698 struct strClass DEFTABLE(tabClass,NUM_CLASSES); /* table of class records */
699 struct strInst far *tabInst; /* (pointer to) table of instances */
701 Class newClass(t) /* add new class to class table */
703 if (classHw-CLASSMIN >= NUM_CLASSES) {
704 ERRMSG(0) "Class storage space exhausted"
707 cclass(classHw).text = t;
708 cclass(classHw).arity = 0;
709 cclass(classHw).kinds = NIL;
710 cclass(classHw).head = NIL;
711 cclass(classHw).dcon = NIL;
712 cclass(classHw).supers = NIL;
713 cclass(classHw).dsels = NIL;
714 cclass(classHw).members = NIL;
715 cclass(classHw).dbuild = NIL;
716 cclass(classHw).defaults = NIL;
717 cclass(classHw).instances = NIL;
718 classes=cons(classHw,classes);
719 cclass(classHw).mod = currentModule;
720 module(currentModule).classes=cons(classHw,module(currentModule).classes);
724 Class classMax() { /* Return max Class in use ... */
725 return classHw; /* This is a bit ugly, but it's not*/
726 } /* worth a lot of effort right now */
728 Class findClass(t) /* look for named class in table */
732 for (cs=classes; nonNull(cs); cs=tl(cs)) {
734 if (cclass(cl).text==t)
740 Class addClass(c) /* Insert Class in class list - if no clash caused */
742 Class oldc = findClass(cclass(c).text);
744 classes=cons(c,classes);
745 module(currentModule).classes=cons(c,module(currentModule).classes);
751 Class findQualClass(c) /* look for (possibly qualified) class in class list */
753 if (!isQualIdent(c)) {
754 return findClass(textOf(c));
757 Module m = findQualifier(qmodOf(c));
759 if (isNull(m)) return NIL;
760 for(es=module(m).exports; nonNull(es); es=tl(es)) {
762 if (isPair(e) && isClass(fst(e)) && cclass(fst(e)).text==t)
769 Inst newInst() { /* add new instance to table */
770 if (instHw-INSTMIN >= NUM_INSTS) {
771 ERRMSG(0) "Instance storage space exhausted"
774 inst(instHw).kinds = NIL;
775 inst(instHw).head = NIL;
776 inst(instHw).specifics = NIL;
777 inst(instHw).implements = NIL;
778 inst(instHw).builder = NIL;
779 inst(instHw).mod = currentModule;
784 Inst findFirstInst(tc) /* look for 1st instance involving */
785 Tycon tc; { /* the type constructor tc */
786 return findNextInst(tc,INSTMIN-1);
789 Inst findNextInst(tc,in) /* look for next instance involving*/
790 Tycon tc; /* the type constructor tc */
791 Inst in; { /* starting after instance in */
792 while (++in < instHw) {
793 Cell pi = inst(in).head;
794 for (; isAp(pi); pi=fun(pi))
795 if (typeInvolves(arg(pi),tc))
801 static Bool local typeInvolves(ty,tc) /* Test to see if type ty involves */
802 Type ty; /* type constructor/tuple tc. */
805 || (isAp(ty) && (typeInvolves(fun(ty),tc)
806 || typeInvolves(arg(ty),tc)));
809 /* --------------------------------------------------------------------------
812 * Various parts of the system use a stack of cells. Most of the stack
813 * operations are defined as macros, expanded inline.
814 * ------------------------------------------------------------------------*/
816 Cell DEFTABLE(cellStack,NUM_STACK); /* Storage for cells on stack */
817 StackPtr sp; /* stack pointer */
819 Void hugsStackOverflow() { /* Report stack overflow */
820 ERRMSG(0) "Control stack overflow"
824 /* --------------------------------------------------------------------------
827 * A Module represents a user defined module.
829 * Note: there are now two lookup mechanisms in the system:
831 * 1) The exports from a module are stored in a big list.
832 * We resolve qualified names, and import lists by linearly scanning
835 * 2) Unqualified imports and local definitions for the current module
836 * are stored in hash tables (tyconHash and nameHash) or linear lists
839 * ------------------------------------------------------------------------*/
841 static Module moduleHw; /* next unused Module */
842 struct Module DEFTABLE(tabModule,NUM_MODULE); /* Module storage */
843 Module currentModule; /* Module currently being processed*/
845 Bool isValidModule(m) /* is m a legitimate module id? */
847 return (MODMIN <= m && m < moduleHw);
850 Module newModule(t) /* add new module to module table */
852 if (moduleHw-MODMIN >= NUM_MODULE) {
853 ERRMSG(0) "Module storage space exhausted"
856 module(moduleHw).text = t; /* clear new module record */
857 module(moduleHw).qualImports = NIL;
858 module(moduleHw).exports = NIL;
859 module(moduleHw).tycons = NIL;
860 module(moduleHw).names = NIL;
861 module(moduleHw).classes = NIL;
862 module(moduleHw).objectFile = 0;
866 Module findModule(t) /* locate Module in module table */
869 for(m=MODMIN; m<moduleHw; ++m) {
870 if (module(m).text==t) {
877 Module findModid(c) /* Find module by name or filename */
880 case STRCELL : { Script s = scriptThisFile(snd(c));
881 return (s==-1) ? NIL : moduleOfScript(s);
883 case CONIDCELL : return findModule(textOf(c));
884 default : internal("findModid");
888 static local Module findQualifier(t) /* locate Module in import list */
891 if (t==module(modulePreludeHugs).text) {
892 /* The Haskell report (rightly) forbids this.
893 * We added it to let the Prelude refer to itself
894 * without having to import itself.
896 return modulePreludeHugs;
898 for (ms=module(currentModule).qualImports; nonNull(ms); ms=tl(ms)) {
899 if (textOf(fst(hd(ms)))==t) {
906 Void setCurrModule(m) /* set lookup tables for current module */
909 if (m!=currentModule) {
910 currentModule = m; /* This is the only assignment to currentModule */
911 for (i=0; i<TYCONHSZ; ++i) {
914 mapProc(hashTycon,module(m).tycons);
915 for (i=0; i<NAMEHSZ; ++i) {
918 mapProc(hashName,module(m).names);
919 classes = module(m).classes;
923 /* --------------------------------------------------------------------------
924 * Script file storage:
926 * script files are read into the system one after another. The state of
927 * the stored data structures (except the garbage-collected heap) is recorded
928 * before reading a new script. In the event of being unable to read the
929 * script, or if otherwise requested, the system can be restored to its
930 * original state immediately before the file was read.
931 * ------------------------------------------------------------------------*/
933 typedef struct { /* record of storage state prior to */
934 Text file; /* reading script/module */
953 static Void local showUse(msg,val,mx)
956 Printf("%6s : %d of %d (%d%%)\n",msg,val,mx,(100*val)/mx);
960 static Script scriptHw; /* next unused script number */
961 static script scripts[NUM_SCRIPTS]; /* storage for script records */
963 Script startNewScript(f) /* start new script, keeping record */
964 String f; { /* of status for later restoration */
965 if (scriptHw >= NUM_SCRIPTS) {
966 ERRMSG(0) "Too many script files in use"
970 showUse("Text", textHw, NUM_TEXT);
971 showUse("Syntax", syntaxHw, NUM_SYNTAX);
972 showUse("Module", moduleHw-MODMIN, NUM_MODULE);
973 showUse("Tycon", tyconHw-TYCMIN, NUM_TYCON);
974 showUse("Name", nameHw-NAMEMIN, NUM_NAME);
975 showUse("Class", classHw-CLASSMIN, NUM_CLASSES);
976 showUse("Inst", instHw-INSTMIN, NUM_INSTS);
978 showUse("Ext", extHw-EXTMIN, NUM_EXT);
982 scripts[scriptHw].file = findText( f ? f : "<nofile>" );
983 scripts[scriptHw].textHw = textHw;
984 scripts[scriptHw].nextNewText = nextNewText;
985 scripts[scriptHw].nextNewDText = nextNewDText;
986 scripts[scriptHw].syntaxHw = syntaxHw;
987 scripts[scriptHw].moduleHw = moduleHw;
988 scripts[scriptHw].tyconHw = tyconHw;
989 scripts[scriptHw].nameHw = nameHw;
990 scripts[scriptHw].classHw = classHw;
991 scripts[scriptHw].instHw = instHw;
993 scripts[scriptHw].dictHw = dictHw;
996 scripts[scriptHw].extHw = extHw;
1001 #define scriptThis(nm,t,tag) Script nm(x) \
1005 && x>=scripts[s].tag) \
1009 scriptThis(scriptThisName,Name,nameHw)
1010 scriptThis(scriptThisTycon,Tycon,tyconHw)
1011 scriptThis(scriptThisInst,Inst,instHw)
1012 scriptThis(scriptThisClass,Class,classHw)
1015 Module lastModule() { /* Return module in current script file */
1016 return (moduleHw-1);
1019 static Module local moduleOfScript(s)
1021 return scripts[s-1].moduleHw;
1024 String fileOfModule(m)
1027 for(s=0; s<scriptHw; ++s) {
1028 if (scripts[s].moduleHw == m) {
1029 return textToStr(scripts[s].file);
1035 static Script local scriptThisFile(f)
1038 for (s=0; s < scriptHw; ++s) {
1039 if (scripts[s].file == f) {
1046 Void dropScriptsFrom(sno) /* Restore storage to state prior */
1047 Script sno; { /* to reading script sno */
1048 if (sno<scriptHw) { /* is there anything to restore? */
1050 textHw = scripts[sno].textHw;
1051 nextNewText = scripts[sno].nextNewText;
1052 nextNewDText = scripts[sno].nextNewDText;
1053 syntaxHw = scripts[sno].syntaxHw;
1054 tyconHw = scripts[sno].tyconHw;
1055 nameHw = scripts[sno].nameHw;
1056 classHw = scripts[sno].classHw;
1057 instHw = scripts[sno].instHw;
1059 dictHw = scripts[sno].dictHw;
1062 extHw = scripts[sno].extHw;
1065 for (i=moduleHw; i >= scripts[sno].moduleHw; --i) {
1066 if (module(i).objectFile) {
1067 printf("closing objectFile for module %d\n",i);
1068 dlclose(module(i).objectFile);
1071 moduleHw = scripts[sno].moduleHw;
1073 for (i=0; i<TEXTHSZ; ++i) {
1075 while (j<NUM_TEXTH && textHash[i][j]!=NOTEXT
1076 && textHash[i][j]<textHw)
1079 textHash[i][j] = NOTEXT;
1083 for (i=0; i<TYCONHSZ; ++i) {
1086 for (i=0; i<NAMEHSZ; ++i) {
1090 for (i=CLASSMIN; i<classHw; i++) {
1091 List ins = cclass(i).instances;
1094 while (nonNull(ins)) {
1095 List temp = tl(ins);
1096 if (hd(ins)<instHw) {
1102 cclass(i).instances = rev(is);
1109 /* --------------------------------------------------------------------------
1112 * Provides a garbage collectable heap for storage of expressions etc.
1114 * Now incorporates a flat resource: A two-space collected extension of
1115 * the heap that provides storage for contiguous arrays of Cell storage,
1116 * cooperating with the garbage collection mechanisms for the main heap.
1117 * ------------------------------------------------------------------------*/
1119 Int heapSize = DEFAULTHEAP; /* number of cells in heap */
1120 Heap heapFst; /* array of fst component of pairs */
1121 Heap heapSnd; /* array of snd component of pairs */
1124 Bool consGC = TRUE; /* Set to FALSE to turn off gc from*/
1125 /* C stack; use with extreme care! */
1126 Int cellsRecovered; /* number of cells recovered */
1128 static Cell freeList; /* free list of unused cells */
1129 static Cell lsave, rsave; /* save components of pair */
1133 static Int markCount, stackRoots;
1135 #define initStackRoots() stackRoots = 0
1136 #define recordStackRoot() stackRoots++
1149 #define start() markCount = 0
1150 #define end(thing,rs) \
1152 printf("GC: %-18s: %4d cells, %4d roots.\n", thing, markCount, rs); \
1155 #define recordMark() markCount++
1157 #else /* !GC_STATISTICS */
1162 #define initStackRoots()
1163 #define recordStackRoot()
1166 #define end(thing,root)
1167 #define recordMark()
1169 #endif /* !GC_STATISTICS */
1171 Cell pair(l,r) /* Allocate pair (l, r) from */
1172 Cell l, r; { /* heap, garbage collecting first */
1173 Cell c = freeList; /* if necessary ... */
1185 freeList = snd(freeList);
1191 Void overwrite(dst,src) /* overwrite dst cell with src cell*/
1192 Pair dst, src; { /* both *MUST* be pairs */
1193 assert(isPair(dst) && isPair(src));
1194 fst(dst) = fst(src);
1195 snd(dst) = snd(src);
1198 Void overwrite2(dst,src1,src2) /* overwrite dst cell with src cell*/
1201 assert(isPair(dst));
1207 static Int marksSize;
1209 Cell markExpr(c) /* External interface to markCell */
1211 return isGenPair(c) ? markCell(c) : c;
1214 static Cell local markCell(c) /* Traverse part of graph marking */
1215 Cell c; { /* cells reachable from given root */
1216 /* markCell(c) is only called if c */
1218 { register place = placeInSet(c);
1219 register mask = maskInSet(c);
1220 if (marks[place]&mask)
1223 marks[place] |= mask;
1228 if (isGenPair(fst(c))) {
1229 fst(c) = markCell(fst(c));
1232 else if (isNull(fst(c)) || fst(c)>=BCSTAG)
1238 static Void local markSnd(c) /* Variant of markCell used to */
1239 Cell c; { /* update snd component of cell */
1240 Cell t; /* using tail recursion */
1242 ma: t = c; /* Keep pointer to original pair */
1247 { register place = placeInSet(c);
1248 register mask = maskInSet(c);
1249 if (marks[place]&mask)
1252 marks[place] |= mask;
1257 if (isGenPair(fst(c))) {
1258 fst(c) = markCell(fst(c));
1261 else if (isNull(fst(c)) || fst(c)>=BCSTAG)
1266 Void markWithoutMove(n) /* Garbage collect cell at n, as if*/
1267 Cell n; { /* it was a cell ref, but don't */
1268 /* move cell so we don't have */
1269 /* to modify the stored value of n */
1276 Void garbageCollect() { /* Run garbage collector ... */
1277 Bool breakStat = breakOn(FALSE); /* disable break checking */
1282 jmp_buf regs; /* save registers on stack */
1286 for (i=0; i<marksSize; ++i) /* initialise mark set to empty */
1289 everybody(MARK); /* Mark all components of system */
1291 gcScanning(); /* scan mark set */
1297 for (i=1; i<=heapSize; i++) {
1298 if ((marks[place] & mask) == 0) {
1305 if (++j == bitsPerWord) {
1312 gcRecovered(recovered);
1313 breakOn(breakStat); /* restore break trapping if nec. */
1315 /* can only return if freeList is nonempty on return. */
1316 if (recovered<minRecovery || isNull(freeList)) {
1317 ERRMSG(0) "Garbage collection fails to reclaim sufficient space"
1320 cellsRecovered = recovered;
1323 /* --------------------------------------------------------------------------
1324 * Code for saving last expression entered:
1326 * This is a little tricky because some text values (e.g. strings or variable
1327 * names) may not be defined or have the same value when the expression is
1328 * recalled. These text values are therefore saved in the top portion of
1330 * ------------------------------------------------------------------------*/
1332 static Cell lastExprSaved; /* last expression to be saved */
1334 Void setLastExpr(e) /* save expression for later recall*/
1336 lastExprSaved = NIL; /* in case attempt to save fails */
1337 savedText = NUM_TEXT;
1338 lastExprSaved = lowLevelLastIn(e);
1341 static Cell local lowLevelLastIn(c) /* Duplicate expression tree (i.e. */
1342 Cell c; { /* acyclic graph) for later recall */
1343 if (isPair(c)) /* Duplicating any text strings */
1344 if (isBoxTag(fst(c))) /* in case these are lost at some */
1345 switch (fst(c)) { /* point before the expr is reused */
1351 case STRCELL : return pair(fst(c),saveText(textOf(c)));
1352 default : return pair(fst(c),snd(c));
1355 return pair(lowLevelLastIn(fst(c)),lowLevelLastIn(snd(c)));
1358 return pair(EXTCOPY,saveText(extText(c)));
1364 Cell getLastExpr() { /* recover previously saved expr */
1365 return lowLevelLastOut(lastExprSaved);
1368 static Cell local lowLevelLastOut(c) /* As with lowLevelLastIn() above */
1369 Cell c; { /* except that Cells refering to */
1370 if (isPair(c)) /* Text values are restored to */
1371 if (isBoxTag(fst(c))) /* appropriate values */
1378 case STRCELL : return pair(fst(c),
1379 findText(text+intValOf(c)));
1381 case EXTCOPY : return mkExt(findText(text+intValOf(c)));
1383 default : return pair(fst(c),snd(c));
1386 return pair(lowLevelLastOut(fst(c)),lowLevelLastOut(snd(c)));
1391 /* --------------------------------------------------------------------------
1392 * Miscellaneous operations on heap cells:
1393 * ------------------------------------------------------------------------*/
1395 /* profiling suggests that the number of calls to whatIs() is typically */
1396 /* rather high. The recoded version below attempts to improve the average */
1397 /* performance for whatIs() using a binary search for part of the analysis */
1399 Cell whatIs(c) /* identify type of cell */
1402 register Cell fstc = fst(c);
1403 return isTag(fstc) ? fstc : AP;
1405 if (c<TUPMIN) return c;
1406 if (c>=INTMIN) return INTCELL;
1408 if (c>=NAMEMIN) if (c>=CLASSMIN) if (c>=CHARMIN) return CHARCELL;
1410 else if (c>=INSTMIN) return INSTANCE;
1412 else if (c>=MODMIN) if (c>=TYCMIN) return TYCON;
1414 else if (c>=OFFMIN) return OFFSET;
1416 else if (c>=EXTMIN) return EXT;
1421 register Cell fstc = fst(c);
1422 return isTag(fstc) ? fstc : AP;
1424 if (c>=CHARMIN) return CHARCELL;
1425 if (c>=CLASSMIN) return CLASS;
1426 if (c>=INSTMIN) return INSTANCE;
1427 if (c>=NAMEMIN) return NAME;
1428 if (c>=TYCMIN) return TYCON;
1429 if (c>=MODMIN) return MODULE;
1430 if (c>=OFFMIN) return OFFSET;
1432 if (c>=EXTMIN) return EXT;
1434 if (c>=TUPMIN) return TUPLE;
1439 /* A very, very simple printer.
1440 * Output is uglier than from printExp - but the printer is more
1441 * robust and can be used on any data structure irrespective of
1444 Void print Args((Cell, Int));
1445 Void print(c, depth)
1451 Int tag = whatIs(c);
1455 print(fst(c), depth-1);
1457 print(snd(c), depth-1);
1461 Printf("free(%d)", c);
1464 Printf("int(%d)", intOf(c));
1467 Printf("bignum(%s)", bignumToString(c));
1470 Printf("char('%c')", charOf(c));
1473 Printf("ptr(%p)",ptrOf(c));
1476 Printf("class(%d)", c-CLASSMIN);
1477 if (CLASSMIN <= c && c < classHw) {
1478 Printf("=\"%s\"", textToStr(cclass(c).text));
1482 Printf("instance(%d)", c - INSTMIN);
1485 Printf("name(%d)", c-NAMEMIN);
1486 if (NAMEMIN <= c && c < nameHw) {
1487 Printf("=\"%s\"", textToStr(name(c).text));
1491 Printf("tycon(%d)", c-TYCMIN);
1492 if (TYCMIN <= c && c < tyconHw)
1493 Printf("=\"%s\"", textToStr(tycon(c).text));
1496 Printf("module(%d)", c - MODMIN);
1499 Printf("Offset %d", offsetOf(c));
1502 Printf("Tuple %d", tupleOf(c));
1506 print(snd(c),depth-1);
1510 if (isPair(snd(c)) && isInt(fst(snd(c)))) {
1511 Printf("%d ", intOf(fst(snd(c))));
1512 print(snd(snd(c)),depth-1);
1514 print(snd(c),depth-1);
1531 Printf("{dict %d}",textOf(c));
1537 Printf("{id %s}",textToStr(textOf(c)));
1540 Printf("{qid %s.%s}",textToStr(qmodOf(c)),textToStr(qtextOf(c)));
1544 print(fst(snd(c)),depth-1);
1546 print(snd(snd(c)),depth-1);
1551 print(snd(c),depth-1);
1556 print(snd(c),depth-1);
1561 print(fst(snd(c)),depth-1);
1563 print(snd(snd(c)),depth-1);
1568 print(fst(snd(c)),depth-1);
1570 print(snd(snd(c)),depth-1);
1574 Printf("FromQual(");
1575 print(fst(snd(c)),depth-1);
1577 print(snd(snd(c)),depth-1);
1581 Printf("StgVar%d=",-c);
1582 print(snd(c), depth-1);
1586 print(fst(snd(c)),depth-1);
1588 print(snd(snd(c)),depth-1);
1593 print(fst(snd(c)),depth-1);
1595 print(snd(snd(c)),depth-1);
1600 print(fst(snd(c)),depth-1);
1602 print(snd(snd(c)),depth-1);
1606 Printf("PrimCase(");
1607 print(fst(snd(c)),depth-1);
1609 print(snd(snd(c)),depth-1);
1613 if (isBoxTag(tag)) {
1614 Printf("Tag(%d)=%d", c, tag);
1615 } else if (isConTag(tag)) {
1616 Printf("%d@(%d,",c,tag);
1617 print(snd(c), depth-1);
1620 } else if (c == tag) {
1621 Printf("Tag(%d)", c);
1623 Printf("Tag(%d)=%d", c, tag);
1632 Bool isVar(c) /* is cell a VARIDCELL/VAROPCELL ? */
1633 Cell c; { /* also recognises DICTVAR cells */
1635 (fst(c)==VARIDCELL || fst(c)==VAROPCELL || fst(c)==DICTVAR);
1638 Bool isCon(c) /* is cell a CONIDCELL/CONOPCELL ? */
1640 return isPair(c) && (fst(c)==CONIDCELL || fst(c)==CONOPCELL);
1643 Bool isQVar(c) /* is cell a [un]qualified varop/id? */
1645 if (!isPair(c)) return FALSE;
1648 case VAROPCELL : return TRUE;
1650 case QUALIDENT : return isVar(snd(snd(c)));
1652 default : return FALSE;
1656 Bool isQCon(c) /*is cell a [un]qualified conop/id? */
1658 if (!isPair(c)) return FALSE;
1661 case CONOPCELL : return TRUE;
1663 case QUALIDENT : return isCon(snd(snd(c)));
1665 default : return FALSE;
1669 Bool isQualIdent(c) /* is cell a qualified identifier? */
1671 return isPair(c) && (fst(c)==QUALIDENT);
1674 Bool isIdent(c) /* is cell an identifier? */
1676 if (!isPair(c)) return FALSE;
1681 case CONOPCELL : return TRUE;
1683 case QUALIDENT : return TRUE;
1685 default : return FALSE;
1689 Bool isInt(c) /* cell holds integer value? */
1691 return isSmall(c) || (isPair(c) && fst(c)==INTCELL);
1694 Int intOf(c) /* find integer value of cell? */
1697 return isPair(c) ? (Int)(snd(c)) : (Int)(c-INTZERO);
1700 Cell mkInt(n) /* make cell representing integer */
1702 return isSmall(INTZERO+n) ? INTZERO+n : pair(INTCELL,n);
1706 #if SIZEOF_INTP == SIZEOF_INT
1707 typedef union {Int i; Ptr p;} IntOrPtr;
1713 return pair(PTRCELL,x.i);
1725 /* For 8 byte addresses (used on the Alpha), we'll have to work harder */
1726 #error "PTR_ON_HEAP not supported on this architecture"
1730 String stringNegate( s )
1738 strcpy(&t[1],s); /* ToDo: use strncpy instead */
1743 /* --------------------------------------------------------------------------
1745 * ------------------------------------------------------------------------*/
1747 Int length(xs) /* calculate length of list xs */
1750 for (n=0; nonNull(xs); ++n)
1755 List appendOnto(xs,ys) /* Destructively prepend xs onto */
1756 List xs, ys; { /* ys by modifying xs ... */
1761 while (nonNull(tl(zs)))
1768 List revDupOnto(xs,ys) /* non-destructively prepend xs backwards onto ys */
1771 for( ; nonNull(xs); xs=tl(xs)) {
1772 ys = cons(hd(xs),ys);
1777 List dupListOnto(xs,ys) /* Duplicate spine of list xs onto ys */
1780 return revOnto(revDupOnto(xs,NIL),ys);
1783 List revOnto(xs,ys) /* Destructively reverse elements of*/
1784 List xs, ys; { /* list xs onto list ys... */
1787 while (nonNull(xs)) {
1799 while (nonNull(as) && nonNull(bs) && hd(as)==hd(bs)) {
1803 return (isNull(as) && isNull(bs));
1806 Cell varIsMember(t,xs) /* Test if variable is a member of */
1807 Text t; /* given list of variables */
1809 for (; nonNull(xs); xs=tl(xs))
1810 if (t==textOf(hd(xs)))
1815 Cell intIsMember(n,xs) /* Test if integer n is member of */
1816 Int n; /* given list of integers */
1818 for (; nonNull(xs); xs=tl(xs))
1819 if (n==intOf(hd(xs)))
1824 Cell cellIsMember(x,xs) /* Test for membership of specific */
1825 Cell x; /* cell x in list xs */
1827 for (; nonNull(xs); xs=tl(xs))
1833 Cell cellAssoc(c,xs) /* Lookup cell in association list */
1836 for (; nonNull(xs); xs=tl(xs))
1842 Cell cellRevAssoc(c,xs) /* Lookup cell in range of */
1843 Cell c; /* association lists */
1845 for (; nonNull(xs); xs=tl(xs))
1851 List replicate(n,x) /* create list of n copies of x */
1862 List diffList(xs,ys) /* list difference: xs\ys */
1863 List xs, ys; { /* result contains all elements of */
1864 List result = NIL; /* `xs' not appearing in `ys' */
1865 while (nonNull(xs)) {
1867 if (!cellIsMember(hd(xs),ys)) {
1876 List deleteCell(xs, y) /* copy xs deleting pointers to y */
1880 for(;nonNull(xs);xs=tl(xs)) {
1883 result=cons(x,result);
1889 List take(n,xs) /* destructively truncate list to */
1890 Int n; /* specified length */
1897 while (1<n-- && nonNull(xs))
1904 List splitAt(n,xs) /* drop n things from front of list */
1914 Cell nth(n,xs) /* extract n'th element of list */
1918 for(; n>0 && nonNull(xs); --n, xs=tl(xs)) {
1920 assert(nonNull(xs));
1924 List removeCell(x,xs) /* destructively remove cell from */
1929 return tl(xs); /* element at front of list */
1933 for (; nonNull(curr); prev=curr, curr=tl(prev))
1935 tl(prev) = tl(curr);
1936 return xs; /* element in middle of list */
1940 return xs; /* here if element not found */
1943 /* --------------------------------------------------------------------------
1944 * Operations on applications:
1945 * ------------------------------------------------------------------------*/
1947 Int argCount; /* number of args in application */
1949 Cell getHead(e) /* get head cell of application */
1950 Cell e; { /* set number of args in argCount */
1951 for (argCount=0; isAp(e); e=fun(e))
1956 List getArgs(e) /* get list of arguments in function*/
1957 Cell e; { /* application: */
1958 List as; /* getArgs(f e1 .. en) = [e1,..,en] */
1960 for (as=NIL; isAp(e); e=fun(e))
1961 as = cons(arg(e),as);
1965 Cell nthArg(n,e) /* return nth arg in application */
1966 Int n; /* of function to m args (m>=n) */
1967 Cell e; { /* nthArg n (f x0 x1 ... xm) = xn */
1969 for (n=numArgs(e)-n-1; n>0; n--)
1974 Int numArgs(e) /* find number of arguments to expr */
1977 for (n=0; isAp(e); e=fun(e))
1982 Cell applyToArgs(f,args) /* destructively apply list of args */
1983 Cell f; /* to function f */
1985 while (nonNull(args)) {
1986 Cell temp = tl(args);
1987 tl(args) = hd(args);
1995 /* --------------------------------------------------------------------------
1997 * ------------------------------------------------------------------------*/
2000 static void far* safeFarCalloc Args((Int,Int));
2001 static void far* safeFarCalloc(n,s) /* allocate table storage and check*/
2002 Int n, s; { /* for non-null return */
2003 void far* tab = farCalloc(n,s);
2005 ERRMSG(0) "Cannot allocate run-time tables"
2010 #define TABALLOC(v,t,n) v=(t far*)safeFarCalloc(n,sizeof(t));
2012 #define TABALLOC(v,t,n)
2020 case RESET : clearStack();
2025 if (isNull(lastExprSaved))
2026 savedText = NUM_TEXT;
2031 for (i=NAMEMIN; i<nameHw; ++i) {
2033 mark(name(i).stgVar);
2036 end("Names", nameHw-NAMEMIN);
2039 for (i=MODMIN; i<moduleHw; ++i) {
2040 mark(module(i).tycons);
2041 mark(module(i).names);
2042 mark(module(i).classes);
2043 mark(module(i).exports);
2044 mark(module(i).qualImports);
2046 end("Modules", moduleHw-MODMIN);
2049 for (i=TYCMIN; i<tyconHw; ++i) {
2050 mark(tycon(i).defn);
2051 mark(tycon(i).kind);
2052 mark(tycon(i).what);
2054 end("Type constructors", tyconHw-TYCMIN);
2057 for (i=CLASSMIN; i<classHw; ++i) {
2058 mark(cclass(i).head);
2059 mark(cclass(i).kinds);
2060 mark(cclass(i).dsels);
2061 mark(cclass(i).supers);
2062 mark(cclass(i).members);
2063 mark(cclass(i).defaults);
2064 mark(cclass(i).instances);
2067 end("Classes", classHw-CLASSMIN);
2070 for (i=INSTMIN; i<instHw; ++i) {
2071 mark(inst(i).kinds);
2073 mark(inst(i).specifics);
2074 mark(inst(i).implements);
2076 end("Instances", instHw-INSTMIN);
2079 for (i=0; i<=sp; ++i)
2084 mark(lastExprSaved);
2087 end("Last expression", 3);
2092 end("C stack", stackRoots);
2097 case INSTALL : heapFst = heapAlloc(heapSize);
2098 heapSnd = heapAlloc(heapSize);
2100 if (heapFst==(Heap)0 || heapSnd==(Heap)0) {
2101 ERRMSG(0) "Cannot allocate heap storage (%d cells)",
2106 heapTopFst = heapFst + heapSize;
2107 heapTopSnd = heapSnd + heapSize;
2108 for (i=1; i<heapSize; ++i) {
2112 snd(-heapSize) = NIL;
2118 marksSize = bitArraySize(heapSize);
2119 if ((marks=(Int *)calloc(marksSize, sizeof(Int)))==0) {
2120 ERRMSG(0) "Unable to allocate gc markspace"
2124 TABALLOC(text, char, NUM_TEXT)
2125 TABALLOC(tabSyntax, struct strSyntax, NUM_SYNTAX)
2126 TABALLOC(tyconHash, Tycon, TYCONHSZ)
2127 TABALLOC(tabTycon, struct strTycon, NUM_TYCON)
2128 TABALLOC(nameHash, Name, NAMEHSZ)
2129 TABALLOC(tabName, struct strName, NUM_NAME)
2130 TABALLOC(tabClass, struct strClass, NUM_CLASSES)
2131 TABALLOC(cellStack, Cell, NUM_STACK)
2132 TABALLOC(tabModule, struct Module, NUM_SCRIPTS)
2134 TABALLOC(tabExt, Text, NUM_EXT)
2139 nextNewText = NUM_TEXT;
2140 nextNewDText = (-1);
2141 lastExprSaved = NIL;
2142 savedText = NUM_TEXT;
2143 for (i=0; i<TEXTHSZ; ++i)
2144 textHash[i][0] = NOTEXT;
2151 for (i=0; i<TYCONHSZ; ++i)
2159 for (i=0; i<NAMEHSZ; ++i)
2170 tabInst = (struct strInst far *)
2171 farCalloc(NUM_INSTS,sizeof(struct strInst));
2174 ERRMSG(0) "Cannot allocate instance tables"
2184 /*-------------------------------------------------------------------------*/