rs@uunet.UU.NET (Rich Salz) (07/08/87)
Mod.sources: Volume 10, Number 39 Submitted by: robison@b.cs.uiuc.edu (Arch Robison) Archive-name: ifp/Part06 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh. # The following files will be created: # interp/infun.c # interp/inimport.c # interp/inob.c # interp/inob.h # interp/list.c # interp/main.c # interp/node.c # interp/node.h export PATH; PATH=/bin:$PATH mkdir interp if test -f 'interp/infun.c' then echo shar: over-writing existing file "'interp/infun.c'" fi cat << \SHAR_EOF > 'interp/infun.c' /****** infun.c *******************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: Aug 4, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #include <stdio.h> #include <ctype.h> #include "struct.h" #include "node.h" #include "string.h" #include "inob.h" /* * PATTERN should be 0. Setting it to 1 enables a parser extension * for experimental compiler work. */ #define PATTERN 0 /* * MakeForm * * If correct, create form with node N and function list Funs. * * Output * result = 1 if no error, 0 otherwise */ boolean MakeForm (Correct,N,Funs,InOut) boolean Correct; NodePtr N; ListPtr Funs; ObjectPtr InOut; { #ifdef PARAMBUG /* cure for CRAY C-compiler bug (see struct.h) */ { ListPtr T = Funs; NewList (&T,1L); Funs = T; } #else NewList (&Funs,1L); #endif if (SysError || !Correct) { DelLPtr (Funs); return 0; } else { Funs->Val.Tag = NODE; Funs->Val.Node = CopyNPtr (N); RepTag (InOut,LIST); InOut->List = Funs; return 1; } } /* * InNext * * Input next composition, which should be followed by Token. * * Input * *F = input * End = pointer to MetaPtr to end of list. * Token = token expected. * K = pointer to entry of form being parsed */ boolean InNext (F,End,Token,K,Env) InDesc *F; MetaPtr *End; char *Token; FormEntry *K; ListPtr Env; { NewList (*End,1L); if (SysError || !InComp (F,&(**End)->Val,Env)) return 0; if (!IsTok (F,Token)) { char Error [80]; extern char *sprintf(); (void) sprintf (Error,"'%s' part of '%s' expected", Token,K->FormComment); return InError (F,Error); } *End = &(**End)->Next; return 1; } /* * InPFO * * Input a PFO. * * Input * F = input descriptor pointing to 1st token after 1st keyword of form * K = index of form * Env = environment list * * Output * InOut = form */ private boolean InPFO (F,InOut,K,Env) register InDesc *F; ObjectPtr InOut; FormEntry *K; ListPtr Env; { ListPtr R = NIL; MetaPtr A = &R; boolean Correct; switch (K-FormTable) { case NODE_If: Correct = 0; if (InNext (F,&A,"THEN",K,Env) && InNext (F,&A,"\0",K,Env)) if (IsTok (F,"ELSIF")) { NewList (A,1L); Correct = !SysError && InPFO (F,&(*A)->Val,K,Env); } else if (IsTok (F,"ELSE")) Correct = InNext (F,&A,"END",K,Env); else (void) InError (F,"'ELSE' or 'ELSIF' expected"); break; case NODE_Each: case NODE_RInsert: case NODE_Filter: Correct = InNext (F,&A,"END",K,NIL); break; case NODE_While: Correct = InNext (F,&A,"DO",K,NIL) && InNext (F,&A,"END",K,NIL); break; #if XDEF case NODE_XDef: { ListPtr OldEnv = Env; Correct = 0; NewList (A,1L); if (SysError || !InLHS (F,&(*A)->Val,&Env)) break; if (!IsTok (F,":=")) (void) InError (F,"':=' expected"); else { A = &(*A)->Next; if (!InNext (F,&A,"}",K,OldEnv)) break; NewList (A,1L); if (InSimple (F,&(*A)->Val,Env)) Correct = 1; } break; } #endif case NODE_C: NewList (A,1L); if (Correct = !SysError && InObject (F,&(*A)->Val)) if ((*A)->Val.Tag == BOTTOM) { /* Convert #? to #(null) */ DelLPtr (R); R = NIL; } break; case NODE_Cons: if (!(Correct = IsTok (F,"]"))) { while ((Correct = InNext (F,&A,"\0",K,Env)) && IsTok (F,",")) continue; if (Correct) if (Correct = IsTok (F,"]")); else (void) InError (F,"']' or ',' expected"); } break; #if FETCH case NODE_Fetch: #endif case NODE_Out: NewList (A,1L); Correct = !SysError && InObject (F,&(*A)->Val); break; } return MakeForm (Correct,K->FormNode,R,InOut); } /* * InSelector * * Input * F = input descriptor pointing to selector * * Output * InOut = selector PFO */ private boolean InSelector (F,InOut) register InDesc *F; ObjectPtr InOut; { register ListPtr P; long Index = 0; do Index = 10*Index + (*F->InPtr++) - '0'; while isdigit (*F->InPtr); RepTag (InOut,LIST); InOut->List = NIL; NewList (&InOut->List,2L); if (SysError) { InOut->Tag = BOTTOM; return 0; } P = InOut->List; P->Val.Tag = NODE; P->Val.Node = FormTable [NODE_Sel].FormNode; P = P->Next; P->Val.Tag = INT; P->Val.Int = IsTok (F,"r") ? -Index : Index; return 1; } /* * InSimple * * Read a simple function * * Output * result = 1 iff error occurs, 0 otherwise * InOut = simple function if no error * * A SysError may occur, in which case InOut is unchanged. */ boolean InSimple (F,InOut,Env) InDesc *F; ObjectPtr InOut; ListPtr Env; { static char InFirst[] = { /* First characters of InPrefix */ 'I','E','W','#','[','F','@' #if FETCH ,'^' #endif #if XDEF ,'{' #endif ,'\0' }; register FormEntry *K; extern char *index (); if (Debug & DebugParse) { printf ("InSimple: Env = "); OutList (Env); printf (", F = %s\n",F->InPtr); } InBlanks (F); #ifdef PATTERN if (IsTok (F,"!")) return InObject (F,InOut); #endif /* * The "index" lookup below quickly rejects strings which * cannot be key words. */ if (NULL != index (InFirst,*F->InPtr)) { for (K=FormTable; K < ArrayEnd(FormTable); K++) if (*K->FormInPrefix != '\0' && IsTok (F,K->FormInPrefix)) return InPFO (F,InOut,K,Env); } else if (isdigit (*F->InPtr)) return InSelector (F,InOut); if (!InNode (F,InOut,Env)) return 0; else if (InOut->List == NULL) return InError (F,"'/' not a function"); else return 1; } /* * InComp * * Input a composition */ boolean InComp (F,InOut,Env) register InDesc *F; ObjectPtr InOut; ListPtr Env; { Object X; if (Debug & DebugParse) { printf ("InComp: Env = "); OutList (Env); printf (", F = %s\n",F->InPtr); } X.Tag = BOTTOM; if (!InSimple (F,&X,Env)) return 0; else { InBlanks (F); if (!IsTok (F,"|")) { RepObject (InOut,&X); RepTag (&X,BOTTOM); return !SysError; } else { ListPtr P,R=NIL; boolean Correct; NewList (&R,1L); if (SysError) Correct = 0; else { CopyObject (&(P=R)->Val,&X); RepTag (&X,BOTTOM); do { NewList (&P->Next,1L); Correct = !SysError && InSimple (F,&(P=P->Next)->Val,NIL); InBlanks (F); } while (Correct && IsTok (F,"|")); } return MakeForm (Correct,FormTable[NODE_Comp].FormNode,R,InOut); } } } /* * InDef * * Input a function definition * * Input * FunName = Name of function * Output * InOut = function definition * result = 1 iff successful, 0 otherwise */ boolean InDef (F,FunName,InOut) register InDesc *F; StrPtr FunName; ObjectPtr InOut; { Object Fun,S; Fun.Tag = BOTTOM; S.Tag = BOTTOM; F->InDefFun = FunName; InBlanks (F); if (!IsTok (F,"DEF")) return InError (F,"DEF expected"); else { InBlanks (F); (void) InString (F,&S,NodeDelim,0); if (StrComp (S.String,FunName)) (void) InError (F,"Definition name wrong"); else { InBlanks (F); if (!IsTok (F,"AS")) (void) InError (F,"AS expected"); else { InBlanks (F); if (InComp (F,&Fun,NIL)) { InBlanks (F); if (!IsTok (F,";")) (void) InError (F,"semicolon expected"); else { InBlanks (F); if (*F->InPtr) (void) InError (F,"end of file expected"); else { RepTag (&S,BOTTOM); CopyObject (InOut,&Fun); RepTag (&Fun,BOTTOM); return 1; } } } } } } RepTag (&S,BOTTOM); RepTag (&Fun,BOTTOM); return 0; } /********************************** infun.c **********************************/ SHAR_EOF if test -f 'interp/inimport.c' then echo shar: over-writing existing file "'interp/inimport.c'" fi cat << \SHAR_EOF > 'interp/inimport.c' /****** inimport.c ****************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: Oct 28, 1985 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #include <stdio.h> #include <ctype.h> #include "struct.h" #include "node.h" #include "string.h" #include "inob.h" /* * DoubleDot * * Append a ".." to path list by deleting last element. * * Input * *F = file descriptor * *C = pointer to path list * * Output * result = pointer to last null field, null if error. */ MetaPtr DoubleDot (F,C) InDesc *F; register MetaPtr C; { register MetaPtr A; if (*C == NULL) { (void) InError (F,"Too many ..'s."); return NULL; } else { /* Remove last element from path list R */ do { A = C; C = &(*A)->Next; } while (*C != NULL); DelLPtr (*A); *A = NULL; return A; } } /* * NodeDelim is the set of pathname delimiters. Note that '>' and '<' are not * in the set since they are (perversely) legal function names. */ char NodeDelim[] = " ,[](){}|;:/\t\n"; /* * InNode * * Input a path. A path may represent a module, function, or functional * variable. Local functions are linked if possible to save time and space. * * The EBNF production definition for a node is: * * ["/"] string { "/" (string | "..") } * * Input * *F = input descriptor pointing to path * Env = environment * * Output * InOut = node (path list or node format) or functional variable (string) * *F = input descriptor pointing to next token after path * * A SysError may occur, in which case InOut is unchanged. */ boolean InNode (F,InOut,Env) InDesc *F; ObjectPtr InOut; ListPtr Env; { ListPtr R = NULL; /* path list accumulator */ register MetaPtr A = &R; /* pointer to Next field at end of accumulator */ register NodePtr N; boolean FirstSlash; if (Debug & DebugParse) printf ("InNode: '%s'",F->InPtr); if (!(FirstSlash = *F->InPtr == '/')) { if (IsTok (F,"..")) { if (F->InDefMod != NULL) R = MakePath (F->InDefMod); if (NULL == (A = DoubleDot (F,&R))) goto Error; } else { Object S; /* relative path */ S.Tag = BOTTOM; if (NULL == InString (F,&S,NodeDelim,0)) { if (!SysError) (void) InError (F,"path expected"); goto Error; } if (!IsTok (F,"/")) { for (; Env!=NULL; Env=Env->Next) if (ObEqual (&Env->Val,&S)) { RepObject (InOut,&Env->Val); /* functional variable */ return 1; } N = FindNode (F->InDefMod,S.String); /* local function */ if (N != NULL) { if (N->NodeType == IMPORT) { /* Imported function - resolve alias */ RepObject (InOut,&N->NodeData.NodeImp.ImpDef); } else { /* Local function already linked */ RepTag (InOut,NODE); InOut->Node = CopyNPtr (N); } RepTag (&S,BOTTOM); return 1; } } if (F->InDefMod != NULL) R = MakePath (F->InDefMod); while (*A != NULL) A = &(*A)->Next; NewList (A,1L); (*A)->Val.Tag = STRING; (*A)->Val.String = S.String; } } while (IsTok (F,"/")) { if (IsTok (F,"..")) if (NULL == (A = DoubleDot (F,&R))) return 0; else continue; else { NewList (A,1L); if (SysError) goto Error; if (NULL == InString (F,&(*A)->Val,NodeDelim,0)) { if (SysError) goto Error; else if (*F->InPtr != '/' && FirstSlash) { (void) DoubleDot (F,&R); break; } else { (void) InError (F,"Invalid path name"); goto Error; } } A = &(*A)->Next; } FirstSlash = 0; } RepTag (InOut,LIST); InOut->List = R; return 1; Error: DelLPtr (R); return 0; } /* * InImport * * Input from an import file. * * An import file has the following format: * * { 'FROM' path 'IMPORT' string {,string} ';' } * * Input * F = input * M = pointer to module node */ void InImport (F,M) register InDesc *F; register NodePtr M; { Object Path,Def; register NodePtr N; MetaPtr A; F->InDefFun = NULL; Path.Tag = BOTTOM; Def.Tag = BOTTOM; while (*F->InPtr) { if (!IsTok (F,"FROM")) { (void) InError (F,"FROM expected"); break; } (void) InNode (F,&Path,NIL); if (!IsTok (F,"IMPORT")) { (void) InError (F,"IMPORT expected"); break; } while (1) { if (NULL == InString (F,&Def," ,;\n",0)) { if (!SysError) (void) InError (F,"function name expected"); goto Return; } N = MakeChild (M,Def.String); switch (N->NodeType) { case IMPORT: (void) InError (F,"duplicate imported identifier"); break; case DEF: if (N->NRef > 1) { (void) InError (F,"identifies function elsewhere"); break; } /* else continue on down to NEWNODE */ case NEWNODE: { extern MetaPtr MakeCopy (); N->NodeType = IMPORT; N->NodeData.NodeImp.ImpDef.Tag = LIST; A = MakeCopy (&N->NodeData.NodeImp.ImpDef.List, Path.List); NewList (A,1L); RepObject (&(*A)->Val,&Def); break; } } if (IsTok (F,";")) break; if (!IsTok (F,",")) { (void) InError (F,"comma or semicolon expected"); goto Return; } } } Return: RepTag (&Path,BOTTOM); RepTag (&Def,BOTTOM); return; } /******************************* inimport.c *******************************/ SHAR_EOF if test -f 'interp/inob.c' then echo shar: over-writing existing file "'interp/inob.c'" fi cat << \SHAR_EOF > 'interp/inob.c' /****** inob.c ********************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: Aug 6, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ /*************** object input parser (recursive descent) ***************/ #include <stdio.h> #include <ctype.h> #include "struct.h" #include "node.h" #include "string.h" #include "inob.h" /* * ObDelim * * Theses characters delimit objects. * Compare with NodeDelim in inimport.c */ private char ObDelim[] = " ,<>|[](){};:\t\n"; /* * InBlanks * * Skip to first non-blank character not in comment. * * Input * F = input descriptor * * Output * F = input descriptor pointing to non-blank character */ void InBlanks (F) register InDesc *F; { while (1) { while (1) { if (!*F->InPtr) if (F->InLineNum >= 0) if (NULL != fgets (F->InBuf,INBUFSIZE,F->InFile)) { F->InPtr = F->InBuf; F->InLineNum++; } if (!isspace (*F->InPtr)) break; F->InPtr++; } if (*F->InPtr == '(' && F->InPtr[1] == '*') { F->ComLevel++; F->InPtr+=2; } else if (*F->InPtr == '*' && F->InPtr[1] == ')') { F->ComLevel--; F->InPtr+=2; } else if (F->ComLevel && *F->InPtr) F->InPtr++; else break; } } /* * IsTok * * Check if next token in input is S. Skip if found. */ boolean IsTok (F,S) InDesc *F; register char *S; { register char *T; for (T = F->InPtr; *S; S++,T++) if (*S != *T) return 0; /* Check if alphabetic token is prefix of longer token */ if (isalpha (T[-1]) && isalpha (T[0])) return 0; F->InPtr = T; InBlanks (F); return 1; } /* * InString * * Input a string. * * Input * *F = input descriptor pointing to first character of string * Delim = string of non-alphanumeric delimiters * Quoted = skip closing delimiter * * Output * *F = input descriptor pointing to next token after string * X = string object * result = pointer to string, NULL if SysError or empty string. * * A SysError may occur, in which case X = bottom. */ StrPtr InString (F,X,Delim,Quoted) register InDesc *F; ObjectPtr X; char *Delim; boolean Quoted; { CharPtr U; register char C; RepTag (X,STRING); X->String = NULL; CPInit (&U,&X->String); do { extern char *index (); C = *F->InPtr++; if (!isalnum (C) && NULL != index (Delim,C)) C = '\0'; CPAppend (&U,C); if (SysError) {RepTag (X,BOTTOM); return NULL;} } while (C); if (!Quoted) F->InPtr--; InBlanks (F); return X->String; } /* * InList * * Input a list * * Input * F = input descriptor pointing to first token after '<' * * Output * result = true iff no error occurs * *X = sequence, or unchanged if error occurs. */ private boolean InList (F,X) register InDesc *F; ObjectPtr X; { ListPtr R=NULL; register MetaPtr A = &R; while (!IsTok (F,">")) { if (!*F->InPtr) { DelLPtr (R); return InError (F,"unfinished sequence"); } NewList (A,1L); if (SysError || !InObject (F,&(*A)->Val)) { DelLPtr (R); return 0; } A = & (*A)->Next; (void) IsTok (F,","); } RepTag (X,LIST); X->List = R; return 1; } /* * InObject * * Read an object. * * Input * *F = input descriptor pointing to object * * Output * *F = input descriptor pointing to next token * result = true iff object is read successfully. * * A SysError may occur, in which case X is unchanged. */ boolean InObject (F,X) register InDesc *F; register ObjectPtr X; { if (IsTok (F,"<")) return InList (F,X); else if (IsTok (F,"(")) { (void) InComp (F,X,NIL); if (!IsTok (F,")")) return InError (F,"')' expected"); } else { /* Input atom */ static char Delim[2] = {'\0','\0'}; *Delim = *F->InPtr; if (*Delim == '\"' || *Delim == '\'') { F->InPtr++; (void) InString (F,X,Delim,1); } else { FPint K; register StrPtr S = InString (F,X,ObDelim,0); if (S == NULL) return SysError || InError (F,"object expected"); if (S->StrChar[1] == '\0') switch (S->StrChar[0]) { case 'f': RepBool (X,0); return 1; case 't': RepBool (X,1); return 1; case '?': RepTag (X,BOTTOM); return 1; } if (StrToFloat (X) && !GetFPInt (X,&K)) { X->Tag = INT; X->Int = K; } } } return 1; } /* * InitIn * * Initialize input descriptor for node N and file FileDesc. * Advance the input pointer to the first token. * * Input * *F = input descriptor * M = module pointer * FileDesc = open file descriptor * LineNum = 0 for normal input, -1 if single-line mode */ void InitIn (F,M,FileDesc,LineNum) register InDesc *F; NodePtr M; FILE *FileDesc; int LineNum; { F->InFile = FileDesc; F->InLineNum= LineNum; F->InPtr = F->InBuf; *F->InPtr = '\0'; F->InDefMod = M; F->ComLevel = 0; InBlanks (F); } /******************************* end of inob.c *******************************/ SHAR_EOF if test -f 'interp/inob.h' then echo shar: over-writing existing file "'interp/inob.h'" fi cat << \SHAR_EOF > 'interp/inob.h' /****** inob.h ********************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: Sept 9, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #define INBUFSIZE 255 /* 65 <= INBUFSIZE <= 255 for DOS */ /* * InDesc * * Input descriptor. * * Currently, there are three forms of IFP input: * * 1. Definition files * 2. Import files * 3. Terminal input * * All three forms are managed by input descriptors. An input descriptor * buffers the file, and keeps track of context (e.g. line number). */ typedef struct { char *InPtr; /* Pointer to current character being scanned */ int InLineNum; /* Line number of line being read [1] */ int ComLevel; /* Current comment nesting level [2] */ NodePtr InDefMod; /* Module node of current definition being read */ StrPtr InDefFun; /* Name of current definition */ FILE *InFile; /* File descriptor of file being read */ char InBuf[INBUFSIZE]; /* Buffer for current line being scanned */ } InDesc; /* * Footnotes * * [1] A line number of -1 indicates unnumbered lines, i.e. terminal input. * * [2] ComLevel should always be zero outside of function "InBlanks". * A non-zero value indicates an "open comment" error. */ extern StrPtr InString (); extern char NodeDelim[]; /******************************* end of inob.h *******************************/ SHAR_EOF if test -f 'interp/list.c' then echo shar: over-writing existing file "'interp/list.c'" fi cat << \SHAR_EOF > 'interp/list.c' /****** list.c ********************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: Jan 15, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #include <stdio.h> #include "struct.h" #include "node.h" #include "umax.h" #include "string.h" #include "stats.h" /* * FreeList * * ListCells in free-list always contain: * * LRef == LRefOne * Val.Tag == BOTTOM * Next == pointer to next cell in free list. */ ListPtr FreeList = NULL; #define LRefAdd(P,Delta) ((P)->LRef+=(Delta)) /*************** Fundamental List Manipulation Routines ***************/ private ListPtr FixCopyLPtr (); /* forward reference */ /* * Rot3 */ void Rot3 (A,B,C) MetaPtr A,B,C; { register ListPtr P; P = *A; *A = *B; *B = *C; *C = P; } /* * ListLength * * Input * P = pointer to list * * Output * result = length of list */ long ListLength (P) register ListPtr P; { register long N; for (N=0; P!=NULL; P=P->Next) N++; return N; } /* * CopyObject * * Copy object: X := Y * * A SysError may occur. */ void CopyObject (X,Y) ObjectPtr X,Y; { register ListPtr P; switch (X->Tag = Y->Tag) { case BOTTOM: break; case BOOLEAN: X->Bool = Y->Bool; break; case INT: X->Int = Y->Int; break; case FLOAT: X->Float = Y->Float; break; case LIST: /* CopyLPtr expanded inline for speed */ P = Y->List; if (P!=NULL && LRefAdd (P,1) == LRefOne-1) /* * This won't work for multiprocessor version * since other processors will not detect overflow. */ P = FixCopyLPtr (P); X->List = P; break; case STRING: X->String = CopySPtr (Y->String); break; case NODE: X->Node = CopyNPtr (Y->Node); break; } } /* * NewList * * Point *A to list of N cells with last cell's Next set to old value of *A. * * Each cell value is set to BOTTOM * * A SysError may occur, in which case *A remains unchanged. * * Implementation note: * (x >= 0) is faster than (x > 0) on 16-bit machines since only * the sign bit must be checked. */ void NewList (A,N) MetaPtr A; register long N; { extern ListPtr AllocListPage (); register MetaPtr B; ListPtr P; Stat (StatNewList (N)); if (--N >= 0) { B = &FreeList; do { if (*B == NULL && (*B = AllocListPage ()) == NULL) { SysError = NO_LIST_FREE; printf ("NO MORE LIST CELLS LEFT\n"); return; } B = &(*B)->Next; } while (--N >= 0); P = FreeList; FreeList = *B; *B = *A; *A = P; } } /* * Repeat * * Create a new list containing N copies of an object * * Output * result = pointer to list * * A SysError may occur, in which case NULL is returned. */ ListPtr Repeat (X,N) register ObjectPtr X; long N; { ListPtr P=NULL; register ListPtr Q; NewList (&P,N); if (!SysError) for (Q=P; Q!=NULL; Q=Q->Next) CopyObject (&Q->Val,X); return P; } /* * DelLPtr * * Delete a list pointer: decrement reference count and return to free-list * if not used anymore. * * Routine is "vectorized" in that it is optimized to return long lists * to the freelist. */ void DelLPtr (P) register ListPtr P; { register ListPtr Q,R; Stat (StatDelLPtr (P)); for (R=P; R!=NULL; R=R->Next) { if (R->LRef != LRefOne) { R->LRef--; break; } if (!Scalar (R->Val.Tag)) { switch (R->Val.Tag) { case LIST: DelLPtr (R->Val.List); break; case STRING: DelSPtr (R->Val.String); break; case NODE: DelNPtr (R->Val.Node); break; } R->Val.Tag = BOTTOM; } Q = R; } if (R != P) { Q->Next = FreeList; FreeList = P; } } /* * CopyLPtr * * Make a copy of a list pointer, incrementing the reference count. * If the reference count would overflow, a new list cell is generated. * * A SysError may occur, in which case the result is NULL. */ ListPtr CopyLPtr (P) ListPtr P; { if (P!=NULL) { if (LRefAdd (P,1) == LRefOne-1) { return FixCopyLPtr (P); } } return P; } /* * FixCopyLPtr * * Copy a list pointer which overflowed. * * Input * P = pointer to list cell */ private ListPtr FixCopyLPtr (P) ListPtr P; { ListPtr Q; /* Reference count overflowed */ LRefAdd (P,-1); Q = CopyLPtr (P->Next); if (SysError) return NULL; NewList (&Q,1L); if (SysError) return NULL; CopyObject (&Q->Val,&P->Val); return Q; } /* * RepTag * * Replace an object tag with another tag. */ void RepTag (Dest,NewTag) ObjectPtr Dest; char NewTag; { switch (Dest->Tag) { case LIST: DelLPtr (Dest->List); break; case STRING: DelSPtr (Dest->String); break; case NODE: DelNPtr (Dest->Node); break; /* default: break; */ } Dest->Tag = NewTag; } /* * RepBool * * Replace an object with a boolean object */ void RepBool (Dest,Value) ObjectPtr Dest; boolean Value; { RepTag (Dest,BOOLEAN); Dest->Bool = Value; } /* * RepObject * * Replace an Object by another Object. * * A SysError may occur. */ boolean RepObject (Y,X) register ObjectPtr Y,X; { Object Z; switch (Z.Tag = Y->Tag) { case LIST: Z.List = Y->List; break; case STRING: Z.String = Y->String; break; case NODE: Z.Node = Y->Node; break; } switch (Y->Tag = X->Tag) { case BOTTOM: break; case BOOLEAN: Y->Bool = X->Bool; break; case INT: Y->Int = X->Int; break; case FLOAT: Y->Float = X->Float; break; case LIST: Y->List = CopyLPtr (X->List); break; case STRING: Y->String = CopySPtr (X->String); break; case NODE: Y->Node = CopyNPtr (X->Node); break; } switch (Z.Tag) { case LIST: DelLPtr (Z.List); break; case STRING: DelSPtr (Z.String); break; case NODE: DelNPtr (Z.Node); break; } } /* * RepLPtr * * Replace pointer variable *A by value B. * * A SysError may occur, in which case *A remains unchanged. */ void RepLPtr (A,P) MetaPtr A; ListPtr P; { P = CopyLPtr (P); /* Copy P first so DelLPtr can't trash *P */ if (SysError) return; DelLPtr (*A); *A = P; } /* * MakeCopy * * Make a copy of a non-empty list. * * Input * P = pointer to list * * Output * *A = pointer to identical list with LRef == LRefOne * result = metapointer to Next field of end of result list * * A SysError may occur, in which case *A remains unchanged. * * All sublist-head reference-counts are incremented if no error occurs. */ MetaPtr MakeCopy (A,P) register ListPtr *A,P; { register ListPtr Q; ListPtr R=NULL; /* R = root of new list */ NewList (&R,ListLength (P)); if (SysError) return NULL; Q = R; while (1) { if (Scalar (P->Val.Tag)) { Q->Val.Data = P->Val.Data; Q->Val.Tag = P->Val.Tag; } else { CopyObject (& Q->Val,& P->Val); if (SysError) {DelLPtr (R); return NULL;}; } P = P->Next; if (P == NULL) break; Q = Q->Next; }; *A = R; return &Q->Next; } /* * CopyTop * * Replace *A with a pointer to a fresh (top level) copy of *A. * * Input * *A = pointer to list * Output * *A = pointer to identical list with LRef == LRefOne for top level * * A SysError may occur, in which case *A remains unchanged. */ void CopyTop (A) register MetaPtr A; { register ListPtr P; while (1) { /* Search for shared part of list */ P = *A; if (P == NULL) return; if (P->LRef != LRefOne) break; Stat (StatRecycle++); A = & P->Next; } (void) MakeCopy (A,P); P->LRef--; if (SysError) (*A)->LRef++; } /* * Copy2Top * * Replace *A with a pointer to a fresh (top 2 levels) of *A. * * Input * *A = pointer to list * Output * *A = pointer to identical list with LRef == LRefOne * for both top level and any immediate sublists. * * A SysError may occur, in which case *A remains unchanged. */ void Copy2Top (A) register MetaPtr A; { register ListPtr P; while (1) { /* Search for shared part of list */ P = *A; if (P == NULL) return; if (P->LRef != LRefOne) break; if (P->Val.Tag == LIST) { CopyTop (&P->Val.List); if (SysError) return; } Stat (StatRecycle++); A = & P->Next; } /* (*A) now points to shared list */ (void) MakeCopy (A,(P = *A)); if (SysError) return; P->LRef--; P = *A; do if (P->Val.Tag == LIST && *(A = &P->Val.List) != NULL) { /* * There must some more elegant way to efficiently merge these * two cases. */ (*A)->LRef--; /* will be incremented by MakeCopy */ (void) MakeCopy (A,*A); if (SysError) return; } while ((P=P->Next) != NULL); } /****************************** end of list.c ******************************/ SHAR_EOF if test -f 'interp/main.c' then echo shar: over-writing existing file "'interp/main.c'" fi cat << \SHAR_EOF > 'interp/main.c' /****** main.c ********************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: Jan 20, 1987 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #include <stdio.h> #include "struct.h" #include "node.h" #include "umax.h" #include "cache.h" #include "stats.h" #if OPSYS!=CTSS #endif static char Version[] = "\nIllinois FP 0.5"; static char Author [] = " Arch D. Robison"; static char Date [] = " Dec 5, 1986\n"; #if OPSYS==UNIX #define OPSYSTEM "UNIX" #endif #if OPSYS==MSDOS #define OPSYSTEM "MS-DOS" #endif #if OPSYS==CTSS #define OPSYSTEM "CTSS" #endif boolean LongPathFlag = 0; #ifdef COMPILE boolean CompilerFlag = 0; /* Enable compiler if set */ boolean RuleFlag = 0; /* Display rules if set */ #endif private void Init () { extern void D_arith (), D_form (), D_pred (), D_misc (), D_seq (), D_ss (), D_subseq (), D_string (), D_cray (), D_vector (); extern void InitString (), InitNode (), InitFile (); extern char RootPath[]; /* from file.c */ #if OPSYS==MSDOS char CWD [64]; #endif #if OPSYS==UNIX extern void EnvGet (); #endif if (Debug & DebugInit) printf ("enter Init\n"); InitString (); #if OPSYS==MSDOS CWDGet (CWD,MAXPATH); #endif #if OPSYS==UNIX EnvGet ("IFProot",RootPath,MAXPATH); /* Check for RootPath */ #endif #if ECACHE InitCache (); #endif InitNode (); D_arith (); D_form (); D_pred (); D_seq (); D_subseq (); D_misc (); D_ss (); D_string (); #if OPSYS==MSDOS InitFile (CWD); #endif #if OPSYS==UNIX || OPSYS==CTSS InitFile (); #endif #ifdef COMPILE if (CompilerFlag) { extern void InitSymTab (), InitCompiler (); InitSymTab (); InitCompiler (); } #endif #ifdef GRAPHICS InitDraw (); /* for CS9000 graphics only */ #endif #if STATS printf (" (stats)"); #endif if (Debug & DebugInit) printf ("exit Init\n"); } extern void UserLoop (); /* * GetOptions * * Process command line options. * * Input * argv = command line arguments * argc = argument count */ private void GetOptions (argc,argv) int argc; char *argv[]; { int k; char *P; for (k=1; k<argc; k++) if (*(P=argv[k]) == '-') while (*P && *++P) switch (*P) { #ifdef COMPILE case 'c': CompilerFlag = 1; break; case 'r': RuleFlag = 1; break; #endif #if DEBUG case 'd': while (*++P) { extern char *index(); static char Opt[] = DebugOpt; char *t = index (Opt,*P); if (t != NULL) Debug |= 1 << (t-Opt); else printf ("[unknown option = -d%c] ",*P); } break; #endif /* DEBUG */ #if ECACHE case 'e': while (*++P) if (*P >= '0' && *P <= '2') Cache[*P-'0'].Enable = 1; else printf ("[unknown -e option = %c] ",*P); break; #endif /* ECACHE */ case 'l': LongPathFlag = 1; break; default: printf ("[unknown option = %c] ",*P); P = ""; break; } } main (argc, argv) int argc; char *argv[]; { printf ("%s: (%s)",Version,OPSYSTEM); (void) fflush (stdout); GetOptions (argc,argv); Init (); printf ("\n\n"); UserLoop (); Terminate(); if (Debug & DebugInit) printf ("normal exit\n"); exit (0); } /************************** end of main.c **************************/ SHAR_EOF if test -f 'interp/node.c' then echo shar: over-writing existing file "'interp/node.c'" fi cat << \SHAR_EOF > 'interp/node.c' /****** node.c ********************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: Nov 23, 1985 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #include <stdio.h> #include "struct.h" #include "node.h" #include "umax.h" #include "string.h" /********************************* NODE RULES ****************************** Function definitions are stored in nodes, which are arranged in a tree structure mimicking the UNIX file structure. Below is an example: Rm | Am---Bi----Cm-------Dd | | Xd Yd--Zd Rm is the root node, with children Am,Bi,Cm, and Dd. Nodes can be one of three types: module (m), import (i), or definition (d). Only definition nodes have a reference count greater than 1. Only module nodes have children. ****************************** end of node rules **************************/ NodePtr RootNode,SysNode,LogicNode,ArithNode; /* Free nodes have NREF == 0 and are linked by NodeSib field */ NodePtr FreeNode = NULL; /* * DelNPtr * * Note: node pointers always have a parent pointer to them, so * we don't have to delete them here. * * Input * N = pointer to node */ void DelNPtr (N) NodePtr N; { rsemaphore_enter (NRefSemaphore); if (N != NULL) N->NRef--; rsemaphore_exit (NRefSemaphore); } /* * CopyNPtr */ NodePtr CopyNPtr (N) NodePtr N; { rsemaphore_enter (NRefSemaphore); if (N != NULL && !++N->NRef) IntError ("CopyNPtr: too many refs"); rsemaphore_exit (NRefSemaphore); return N; } /* * NewNode * * Point *N to new node from free list. The input value of *N is * put in the NodeSib field of the new node. * * A SysError may occur, in which case *N is unchanged. */ private void NewNode (N) NodePtr *N; { extern NodePtr AllocNodePage (); register NodePtr T; rsemaphore_enter (NRefSemaphore); if (FreeNode == NULL && (FreeNode = AllocNodePage ()) == NULL) { printf ("NO MORE NODE CELLS LEFT\n"); SysError = NO_NODE_FREE; } else { T = FreeNode; FreeNode = FreeNode->NodeSib; T->NodeSib = *N; *N = T; } rsemaphore_exit (NRefSemaphore); } /* * FindNode * * Find a node within a module with a specified name. * * Input * M = pointer to module node * S = pointer to string * * Output * result = NULL if node not found, pointer to node otherwise */ NodePtr FindNode (M,S) register NodePtr M; StrPtr S; { if (M->NodeType == MODULE) for (M = M->NodeData.NodeMod.FirstChild; M!=NULL; M=M->NodeSib) if (0==StrComp (M->NodeName,S)) return M; return NULL; } /* * MakePath * * Make the path list for a given node * * Input * *N = module node * Output * *result = path list */ ListPtr MakePath (N) NodePtr N; { ListPtr P; rsemaphore_enter (NRefSemaphore); P = NULL; while (N->NodeParent != NULL) { NewList (&P,1L); P->Val.Tag = STRING; P->Val.String = CopySPtr (N->NodeName); N = N->NodeParent; } rsemaphore_exit (NRefSemaphore); return P; } /* * MakeChild * * Find (or create if necessary) a new child node with a specified name. * * Input * M = Parent node * S = name of child * * Output * N = pointer to child * * A SysError may occur. */ NodePtr MakeChild (M,S) NodePtr M; StrPtr S; { register NodePtr N; rsemaphore_enter (NRefSemaphore); N = FindNode (M,S); if (N==NULL) { NewNode (&M->NodeData.NodeMod.FirstChild); if (SysError) { N = NULL; goto exit; } N = M->NodeData.NodeMod.FirstChild; N->NodeParent = M; N->NodeName = CopySPtr (S); N->NodeType = NEWNODE; } exit: rsemaphore_exit (NRefSemaphore); return N; } /* * Initialize a module node * * Input * M = pointer to new node */ void InitModule (M) register NodePtr M; { M->NodeType = MODULE; M->NodeData.NodeMod.FirstChild = NULL; ReadImport (M); } /* * MakeNode * * Create all nodes required by a path. * * Input * Path = pointer to path list * Type = type to make node if new node * Output * result = pointer to node specified by path or * NULL if an error occurred. */ NodePtr MakeNode (Path,Type) ListPtr Path; int Type; { register NodePtr M; register ListPtr P; rsemaphore_enter (NRefSemaphore); M = RootNode; for (P=Path; P != NULL; P=P->Next) if (P->Val.Tag != STRING) return NULL; else { M = MakeChild (M,P->Val.String); if (M->NodeType == NEWNODE) if (P->Next!=NULL) InitModule (M); else switch (M->NodeType = Type) { case DEF: M->NodeData.NodeDef.DefCode.Tag = BOTTOM; M->NodeData.NodeDef.DefFlags = 0; break; case MODULE: InitModule (M); break; } } rsemaphore_exit (NRefSemaphore); return M; } /* * DelImport * * Delete all information affected by the %IMPORT file for a module node * in preparation for rereading the %IMPORT file. * * Input * M = pointer to module node * * Notes * IMPORT nodes can be returned to the free list since their * reference counts are always 1. */ void DelImport (M) NodePtr M; { register NodePtr *L; register NodePtr N; rsemaphore_enter (NRefSemaphore); for (L = &M->NodeData.NodeMod.FirstChild; (N = *L)!= NULL; ) switch (N->NodeType) { case IMPORT: /* Return IMPORT nodes to free list */ DelSPtr (N->NodeName); RepTag (&N->NodeData.NodeImp.ImpDef,BOTTOM); Rot3 ((MetaPtr) &FreeNode, (MetaPtr) L, (MetaPtr) &N->NodeSib); break; case DEF: /* Delete local function definitions */ if (N->NodeData.NodeDef.DefCode.Tag != CODE) RepTag (&N->NodeData.NodeDef.DefCode,BOTTOM); L = &N->NodeSib; break; case MODULE: L = &N->NodeSib; break; default: printf ("Invalid NodeType in node tree: %d\n",N->NodeType); L = &N->NodeSib; break; } rsemaphore_exit (NRefSemaphore); } /* * LinkPath * * Convert a path list to a node if possible. * * Input * *Def = path list * Type = NodeType value if new node * * Output * *Def = node or not changed if error occurs */ void LinkPath (Path,Type) ObjectPtr Path; int Type; { register NodePtr N; rsemaphore_enter (NRefSemaphore); N = MakeNode (Path->List,Type); if (N != NULL) { RepTag (Path,NODE); Path->Node = CopyNPtr (N); } rsemaphore_exit (NRefSemaphore); } /* * SignExtend * * Sign extend a byte. Not all machines have signed characters. */ #define SignExtend(B) ((((B) + 0x80) & 0xFF) - 0x80) /* * PrimDef * * Define a primitive function * * Input * *F = object code for function * S = name of function * M = module to put function in * K = code parameter value * * Output * result = pointer to node containing function */ /* VARARGS3 */ NodePtr PrimDef (F,S,M,K) int (*F) (); char *S; NodePtr M; char K; { register NodePtr N; StrPtr T; T = MakeString (S); N = MakeChild (M,T); N->NodeType = DEF; N->NodeData.NodeDef.DefCode.Tag = CODE; N->NodeData.NodeDef.DefFlags = 0; N->NodeData.NodeDef.DefCode.Code.CodePtr = F; N->NodeData.NodeDef.DefCode.Code.CodeParam = SignExtend (K); DelSPtr (T); return N; } /* * GroupDef * * Define a group of functions * * Input * T = pointer to table of functions * N = number entries in table * M = module node */ void GroupDef (T,N,M) register OpDef *T; int N; NodePtr M; { while (--N >= 0) (void) PrimDef (T->OpPtr,T->OpName,M,T->OpParam), T++; } /* * Initialize root node and 'sys' subnode. */ void InitNode () { register NodePtr R; if (Debug & DebugInit) printf ("enter InitNode\n"); RootNode = NULL; NewNode (&RootNode); R = RootNode; R->NodeSib = NULL; R->NodeParent = NULL; R->NodeType = MODULE; R->NodeName = MakeString ("ROOT"); R->NodeData.NodeMod.FirstChild = NULL; SysNode = MakeChild (R,MakeString ("sys")); InitModule (SysNode); R = MakeChild (R,MakeString ("math")); InitModule (R); ArithNode = MakeChild (R,MakeString ("arith")); InitModule (ArithNode); LogicNode = MakeChild (R,MakeString ("logic")); InitModule (LogicNode); if (Debug & DebugInit) printf ("exit InitNode\n"); } /****************************** end of node.c ******************************/ SHAR_EOF if test -f 'interp/node.h' then echo shar: over-writing existing file "'interp/node.h'" fi cat << \SHAR_EOF > 'interp/node.h' /****** node.h ********************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.5 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: July 8, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #ifndef INCLUDE_NODE_H #define INCLUDE_NODE_H 1 /* * Define FETCH as 1 to define "fetch" (^k) functional form, 0 otherwise. * Define XDEF as 1 to define "xdef" ({...} f) functional form, 0 otherwise. */ #define FETCH 0 #define XDEF 1 extern ListPtr MakePath (); extern NodePtr CopyNPtr (), FindNode (); extern NodePtr MakeNode (), MakeChild (), PrimDef (); extern NodePtr RootNode, SysNode, ArithNode, LogicNode; extern void DelNPtr (), FormPath (), GroupDef (), LinkPath (); void InitNode (); typedef struct { /* Used for node initialization tables */ char *OpName; char OpParam; int (*OpPtr) (); /* Actually void, but compiler complains about void */ } OpDef; /* in static initializations of this structure */ #define OpCount(OpTable) (sizeof(OpTable)/sizeof(OpTable[0])) extern NodePtr FormNode[]; /* * Subscripts for FormNode * * These must correspond to the entries in the FormOpTable in forms.c */ #define NODE_C 0 #define NODE_Comp 1 #define NODE_Cons 2 #define NODE_Each 3 #define NODE_Fetch 4 #define NODE_Filter (4 + FETCH) #define NODE_If (5 + FETCH) #define NODE_RInsert (6 + FETCH) #define NODE_Out (7 + FETCH) #define NODE_Sel (8 + FETCH) #define NODE_While (9 + FETCH) #define NODE_XDef (9 + FETCH + XDEF) #define FORM_TABLE_SIZE (10 + FETCH + XDEF) typedef struct { NodePtr FormNode; /* Node pointer for form */ char *FormInPrefix; OpDef FormOp; char *FormComment; /* Comment for `expected' error message */ } FormEntry; extern FormEntry FormTable[FORM_TABLE_SIZE]; #endif /****************************** end of node.h ******************************/ SHAR_EOF # End of shell archive exit 0 -- Rich $alz "Anger is an energy" Cronus Project, BBN Labs rsalz@pineapple.bbn.com Moderator, comp.sources.unix sources@uund, d, das