rs@uunet.UUCP (07/08/87)
Mod.sources: Volume 10, Number 38 Submitted by: robison@b.cs.uiuc.edu (Arch Robison) Archive-name: ifp/Part05 #! /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/cache.c # interp/cache.h # interp/command.c # interp/convert.c # interp/debug.c # interp/dos.s # interp/error.c # interp/except.c # interp/file.c # interp/forms.c export PATH; PATH=/bin:$PATH mkdir interp if test -f 'interp/cache.c' then echo shar: over-writing existing file "'interp/cache.c'" fi cat << \SHAR_EOF > 'interp/cache.c' /****** cache.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: July 29, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ /* * NOTE: Function HashOb assumes a FPfloat is either 1x or 2x the size * of a long. */ #include "struct.h" #include "cache.h" #include <stdio.h> #if ECACHE CacheEntry ECache[CACHE_SIZE]; CacheRec Cache [4] = { {0,0,0,0,"Prim"}, {0,0,0,0,"User"}, {0,0,0,0,"PFO"}, {0,0,0,0,"Total"}, }; #define ArraySize(A) (sizeof(A)/sizeof(A[0])) /* * Print the cache statistics on stdout and clear the cache statistics tallies. */ void ShowCache () { CacheRec *C,*T= &Cache[CacheTotal]; CacheEntry *E; int Tally=0; for (E=ECache; E < ArrayEnd(ECache); E++) if (E->EC_Fun != NULL) Tally++; printf ("%d/%d = %g full cache\n", Tally, ArraySize (ECache), (double) Tally / ArraySize (ECache)); T->Enable = 0; for (C= &Cache[0]; C<&Cache[4]; C++) { if (C->Enable) { Cache[CacheTotal].Enable=1; printf ("%s:\t%d hits in %d looks = %g%% hit rate [%d evictions]\n", C->Name,C->Hits,C->Looks, 100.0 * C->Hits / (C->Looks ? C->Looks : 1), C->Evictions); T->Hits += C->Hits; T->Looks += C->Looks; T->Evictions += C->Evictions; C->Hits = C->Looks = C->Evictions = 0; } } if (!T->Enable) printf ("The cache is disabled\n"); } #if DEBUG void PrintCache (Message,E) char *Message; CacheEntry *E; { printf ("ECache %s ",Message); OutObject (&E->EC_In); printf (" : "); OutNode (E->EC_Fun); printf (" -> "); OutObject (&E->EC_Out); printf ("\n"); } #endif /* DEBUG */ /* * HashOb * * HashOb computes an integer function (hash code) of an object. * * Input * X = object * Output * result = hash code */ int HashOb (X) ObjectPtr X; { register long H; register ListPtr P; switch (X->Tag) { case BOTTOM: H = 2305; break; case BOOLEAN: H = X->Bool; break; case INT: H = X->Int * 9; break; case FLOAT: if (sizeof (FPfloat) == 2*sizeof (long)) H = ((long *)&(X->Float))[0] + ((long *)&(X->Float))[1]; else if (sizeof (FPfloat) == sizeof (long)) H = ((long *)&(X->Float))[0]; else fprintf (stderr,"HashOb: can't hash floats on this machine!\n"); break; case STRING: H = (long) X->String; break; case LIST: H = 5298; for (P=X->List; P!=NULL; P=P->Next) H = H * 0x1243 + HashOb (&P->Val); break; case NODE: H = (long) X->Node * 5; break; case CODE: H = (long) X->Code.CodePtr + (long) X->Code.CodeParam; break; default: fprintf (stderr,"HashOb: invalid tag (%d)\n",X->Tag); break; } return H; } ClearCache () /* Clear all entries from the cache. */ { CacheEntry *C; for (C=ECache+CACHE_SIZE; --C >= ECache; ) { RepTag (&C->EC_In, BOTTOM); C->EC_Fun = NULL; RepTag (&C->EC_Out,BOTTOM); } } InitCache () /* Initialize the cache */ { register CacheEntry *E; CacheRec *C; printf (" (cache"); for (C=Cache; C<&Cache[3]; C++) if (C->Enable) printf (" %s",C->Name); printf (")"); for (E=ECache+CACHE_SIZE; --E >= ECache; ) { E->EC_In. Tag = BOTTOM; E->EC_Fun = NULL; E->EC_Out.Tag = BOTTOM; } } #endif /* ECACHE */ SHAR_EOF if test -f 'interp/cache.h' then echo shar: over-writing existing file "'interp/cache.h'" fi cat << \SHAR_EOF > 'interp/cache.h' /****** cache.h *******************************************************/ /** **/ /** University of Illinois **/ /** **/ /** Department of Computer Science **/ /** **/ /** Tool: IFP Version: 0.1 **/ /** **/ /** Author: Arch D. Robison Date: May 1, 1985 **/ /** **/ /** Revised by: Arch D. Robison Date: July 29, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #define ECACHE 0 /* Implement expression cache if defined */ #if ECACHE /* * The expression cache can be turned on selectively for expressions with * primitive functions, user-defined functions, or PFOs. * * Cache[i].Enable = 0/1 to turn off/on cache for expression type i in [0..2]. */ #define CachePrim 0 #define CacheUser 1 #define CachePFO 2 #define CacheTotal 3 typedef struct { boolean Enable; int Looks; /* Number of looks into cache */ int Hits; /* Number of successful looks */ int Evictions; /* Number of evictions */ char *Name; /* "Prim", "User", "PFO", etc.*/ } CacheRec; extern CacheRec Cache[]; #if DEBUG extern void PrintCache (); #endif /* * The expression cache is implemented as a hash table. It * associates outputs with <input,function> pairs. */ #define CACHE_SIZE 1024 /* Must be power of 2 */ /* * EC_Fun.Tag = BOTTOM iff that cache entry is empty */ typedef struct { Object EC_In, EC_Out; NodePtr EC_Fun; } CacheEntry; extern CacheEntry ECache[]; extern int HashOb (); extern void ShowCache (); /* Show cache statistics */ /* * CheckCache * * Parameter * T = &Cache[i] where i is type of function to be cached. * A = call to "apply" with appropriate arguments. */ #define CheckCache(T,A) \ if ((T)->Enable) { \ CacheEntry *C; \ extern int TraceDepth; \ \ (T)->Looks++; \ C = &ECache [(HashOb(InOut) + (long) F->Node) * 0x9B & CACHE_SIZE-1]; \ if (ApplyFun == C->EC_Fun && ObEqual (InOut,&C->EC_In)) { \ if (Debug & DebugCache) PrintCache ("Hit!",C); \ (T)->Hits++; \ if (Trace|SaveTrace) printf ("IBID\n"); \ RepObject (InOut,&C->EC_Out); \ } else { \ if (C->EC_Fun != NULL) { \ (T)->Evictions++; \ if (Debug & DebugCache) PrintCache ("Evict",C); \ } \ C->EC_Fun = NULL; \ RepObject (&C->EC_In,InOut); \ {A;} \ C->EC_Fun = F->Node; \ RepObject (&C->EC_Out,InOut); \ if (Debug & DebugCache) PrintCache ("Load",C); \ } \ } else {A;} #else #define CheckCache(T,A) {A;} #define ClearCache() #endif /***************************** end of cache.h ****************************/ SHAR_EOF if test -f 'interp/command.c' then echo shar: over-writing existing file "'interp/command.c'" fi cat << \SHAR_EOF > 'interp/command.c' /****** command.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 28, 1987 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ /*************************** Command Interpreter **************************/ #include <stdio.h> #include <errno.h> #include "struct.h" #include "node.h" #include "umax.h" #include "inob.h" #include "cache.h" #include "stats.h" #if OPSYS==UNIX #include <strings.h> #include <sys/wait.h> #endif #if OPSYS==MSDOS #include "/usr/include/dos/spawn.h" /* Full name so lint can find it */ #include "/usr/include/dos/string.h" #endif extern char EditorPath [],*EdCommand; extern char *getenv (); extern boolean RefCheck (); /* from apply.c */ #if OPSYS==UNIX extern fork (),execl (); #endif InDesc UserIn; /* * ReadNode */ private NodePtr ReadNode (U) InDesc *U; { Object S; if (!InNode (U,&S,NIL)) return NULL; LinkPath (&S,DEF); if (S.Tag == NODE) return S.Node; else { printf ("Error: "); OutString (S.String); printf (" not defined\n"); return NULL; } } #if REFCHECK /* * ShowRefCheck */ void ShowRefCheck () { Object F; register InDesc *U; U = &UserIn; F.Tag = BOTTOM; (void) InComp (U,&F,NIL); (void) RefCheck ((NodePtr) NULL,&F); RepTag (&F,BOTTOM); } #endif /* * ShowApply */ private void ShowApply (OutGraph) int OutGraph; { Object X,F; register InDesc *U; U = &UserIn; X.Tag = BOTTOM; F.Tag = BOTTOM; if (InObject (U,&X)) { if (!IsTok (U,":")) (void) InError (U,"colon expected"); else { (void) InComp (U,&F,NIL); if (Debug & DebugFile) { printf ("Object = "); OutObject (&X); printf ("\n"); printf ("Function = "); OutFun (&F,MaxInt); printf ("\n"); } if (*U->InPtr) (void) InError (U,"extra character on line"); else { U->InPtr++; ClearCache (); Apply (&X,&F); #ifdef GRAPHICS if (OutGraph) DrawObject (&X); else OutPretty (&X,0); #else OutPretty (&X,0); printf ("\n"); #endif } } } RepTag (&X,BOTTOM); RepTag (&F,BOTTOM); } /* * ExecFile * * Execute a file * * Input * Prog = program to be executed * Arg = argument string */ void ExecFile (Prog,Arg) char *Prog,*Arg; { if (Debug & DebugFile) printf ("ExecFile (%s,%s)\n",Prog,Arg); #if OPSYS==UNIX if (fork ()) (void) wait ((union wait *)NULL); else { if (Debug & DebugFile) printf ("prepare to flush\n"); (void) fflush (stdout); execl (Prog,Prog,Arg,(char *)NULL); perror (Prog); exit (1); } #endif #if OPSYS==MSDOS if (spawnl (P_WAIT,Prog,Prog,Arg,(char *)NULL)) perror (Prog); #endif } void ExecEdit (FileName) char *FileName; { if (Debug & DebugFile) printf ("ExecEdit (%s)\n",FileName); #if OPSYS==UNIX ExecFile (EditorPath,FileName); #endif #if OPSYS==MSDOS { extern char *PathSplit (); char *T; T = PathSplit (FileName); if (T != NULL) ExecFile (EditorPath,T); } #endif } /* * EditRm * * Action depends on ``Edit'' flag: * * Edit * Apply the user's editor to a function or import file. If a function, * delete the function definition from memory. If %IMPORT file, reread it. * * !Edit * Remove a function definition or %IMPORT file. */ private void EditRm (U,Edit) register InDesc *U; boolean Edit; { Object N; char Buf[MAXPATH+1]; static char *Import = "%IMPORT"; if (Debug & DebugFile) printf ("EditRm (%s,%d)\n",U->InPtr,Edit); if (IsTok (U,Import)) { if (Edit) ExecFile (EditorPath,Import); else if (unlink (Import)) perror (Import); DelImport (U->InDefMod); ReadImport (U->InDefMod); } else { N.Tag = BOTTOM; (void) InNode (U,&N,NIL); LinkPath (&N,DEF); /* Kill old source code definition */ if (N.Tag == NODE) switch (N.Node->NodeType) { case DEF: RepTag (&N.Node->NodeData.NodeDef.DefCode,BOTTOM); break; case MODULE: break; } FormPath (&N,Buf,&Buf[MAXPATH]); RepTag (&N,BOTTOM); if (Edit) ExecEdit (Buf); else if (unlink (Buf)) perror (Buf); } } #if OPSYS==UNIX /* * Shell * * Execute a shell command */ void Shell (U) register InDesc *U; { if (Debug & DebugFile) printf ("Shell: '%s'\n",U->InPtr); if (fork ()) (void) wait ((union wait *)NULL); else { (void) fflush (stdout); execl ("/bin/sh","sh","-c",U->InPtr,(char *)NULL); } } #endif #if OPSYS==MSDOS /* * ChDirToCWD * * Set DOS current working directory to IFP current working directory. * * This procedure is a necessary KLUDGE because the current directory * cache mechanism changes the current working directory all over the place. */ void ChDirToCWD () { char Buf[MAXPATH]; extern char *FormNPath (); (void) FormPath (CurWorkDir,Buf,&Buf[MAXPATH]); chdir (Buf); } /* * Directory * * Show the current directory */ void Directory (U) register InDesc *U; { extern char DirPath[]; ChDirToCWD (); ExecFile (DirPath,U->InPtr); } #endif /* * SetDepth * * Set function printing depth used for printing. */ SetDepth (U) register InDesc *U; { Object X; FPint N; extern int TraceDepth; X.Tag = BOTTOM; (void) InObject (U,&X); if (GetFPInt (&X,&N) || N < 0 || N > MaxInt) printf ("Error: depth must be integer in range 0..%d\n",MaxInt); else TraceDepth = N; } /* * SetTrace * * Set or reset function trace flags. */ private void SetTrace (U) register InDesc *U; { NodePtr N; int T; /* phone home */ if (IsTok (U,"on")) T=1; else if (IsTok (U,"off")) T=0; else { printf ("trace [on|off] f1 f2 f3 ... \n"); return; } while (*U->InPtr) { N = ReadNode (U); if (N != NULL) { if (T) N->NodeData.NodeDef.DefFlags |= TRACE; else N->NodeData.NodeDef.DefFlags &= ~TRACE; } else break; } } #if DUMP extern void DumpNode(); #endif void UserLoop () { register InDesc *U; int N; U = &UserIn; while (1) { extern char FPprompt [], *gets(); extern void ResetExcept(); #if OPSYS==MSDOS extern char CWDCache []; CWDCache [0] = '\0'; /* Clear current directory cache */ #endif ResetExcept (); if (Debug & DebugAlloc) { extern ListPtr FreeList; printf ("length (FreeList) = %ld\n",ListLength (FreeList)); } printf ("%s",FPprompt); (void) fflush (stdout); InitIn (U,CurWorkDir,stdin,-1); /* Copy prompt so that error message '^' will point correctly. */ U->InPtr += N = strlen (strcpy (U->InPtr,FPprompt)); (void) fgets (U->InPtr, INBUFSIZE-N, stdin); if (!*U->InPtr || IsTok (U,"exit")) { #if OPSYS==MSDOS ChDirToCWD (); #endif return; } else if (IsTok (U,"depth")) SetDepth (U); else if (IsTok (U,"show")) ShowApply (0); #if HYPERCUBE else if (IsTok (U,"send")) { Object X; ForkFP (); InObject (U,&X); OutBinObject (&X); } #endif #if COMPILE else if (CompilerFlag && IsTok (U,"c")) Compile (U); #endif #if REFCHECK else if (IsTok (U,"check")) ShowRefCheck (); #endif #if ECACHE else if (IsTok (U,"cache")) ShowCache (); #endif #if STATS else if (IsTok (U,"stats")) ShowStats (); #endif else if (IsTok (U,"trace")) SetTrace (U); else if (IsTok (U,EdCommand)) EditRm (U,1); #if DUMP else if (IsTok (U,"dump")) DumpNode (CurWorkDir,0); #endif #ifdef GRAPHICS else if (IsTok (U,"graph")) ShowApply (1); #endif /* else if (IsTok (U,"test")) Test (U); */ #if OPSYS==UNIX else if (IsTok (U,"rm")) EditRm (U,0); else Shell (U); #endif #if OPSYS==MSDOS else if (IsTok (U,"del")) EditRm (U,0); else if (IsTok (U,"dir")) Directory (U); #endif #if OPSYS==MSDOS || OPSYS==CTSS else printf ("Unknown command: %s\n",U->InPtr); #endif } } /************************** end of command.c **************************/ SHAR_EOF if test -f 'interp/convert.c' then echo shar: over-writing existing file "'interp/convert.c'" fi cat << \SHAR_EOF > 'interp/convert.c' /****** convert.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: July 2, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ /* Type conversion functions */ #include <stdio.h> #include <ctype.h> #include "struct.h" #include "string.h" #include <math.h> #define BUFSIZE 80 /* Maximum length of numeric string */ /* * GetFPInt * * Get value of FP integer. * * Input * X = FP object * * Output * *K = FPint value of X * result = error code: 0 = X was converted to integer *K * 1 = X not an integer * 2 = X too big */ int GetFPInt (X,K) ObjectPtr X; FPint *K; { switch (X->Tag) { default: return 1; case INT: *K = X->Int; return 0; case FLOAT: { double F; F = X->Float; if (fabs (F) <= (double) FPMaxInt) { *K = (FPint) F; F -= (double) *K; return fabs (F) >= CompTol; } else return 2; } } } #if OPSYS==CTSS /* * IsFloat * * Determine if a string represents floating point number as defined * by C's atof function. This function is necessary for the CRAY * since there is a bug in sscanf for the CRAY. * * Input * S = string * * Output * result = true iff string represents number. */ int IsFloat (S) register char *S; { int Digits = 0; if (*S == '+' || *S == '-') S++; while (isdigit (*S)) { S++; Digits++; } if (*S == '.') while (isdigit (*++S)) Digits++; if (!Digits) return 0; if (*S == '\0') return 1; if (*S++ != 'e') return 0; if (*S == '+' || *S == '-') S++; while (isdigit (*S)) S++; return *S == '\0'; } #endif /* OPSYS==CTSS */ /* * StrToFloat * * Convert object to float representation if possible. * * Input * *X = object * * Output * *X = new representation of object * result = 1 if *X is float, 0 otherwise. */ boolean StrToFloat (X) ObjectPtr X; { CharPtr U; char Buf[BUFSIZE+1]; double F; #if OPSYS!=CTSS char Term; #endif CPInit (&U,&X->String); (void) CPRead (&U,Buf,BUFSIZE); #if OPSYS==CTSS if (!IsFloat (Buf)) return 0; F = atof (Buf); #else Buf [strlen (Buf)] = '\1'; if (2 != sscanf (Buf,"%lf%c",&F,&Term) || Term != '\1') return 0; #endif RepTag (X,FLOAT); X->Float = (FPfloat) F; return 1; } /* * GetDouble * * Output * result = 0 if *D is valid, 1 otherwise. */ int GetDouble (X,D) ObjectPtr X; double *D; { switch (X->Tag) { case INT: *D = X->Int; return 0; case FLOAT: *D = X->Float; return 0; default: return 1; } } /****************************** end of convert.c *****************************/ SHAR_EOF if test -f 'interp/debug.c' then echo shar: over-writing existing file "'interp/debug.c'" fi cat << \SHAR_EOF > 'interp/debug.c' /****** debug.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: Dec 5, 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 "string.h" #if DEBUG int Debug = 0; /* Print debugging statements if true */ #endif #if DUMP /* * DumpNode * * Print out node N and all its decendants. */ void DumpNode (N,Indent) register NodePtr N; int Indent; { extern void OutIndent (); OutIndent (3*Indent); if (N == NULL) printf ("DumpNode: N = NULL\n"); else { OutString (N->NodeName); switch (N->NodeType) { case NEWNODE: printf ("(new) "); break; case MODULE: printf (" module\n"); for (N = N->NodeData.NodeMod.FirstChild; N!=NULL; N=N->NodeSib) DumpNode (N,Indent+1); break; case DEF: printf (" function"); if (N->NodeData.NodeDef.DefFlags & TRACE) printf ("(trace) "); OutObject (&N->NodeData.NodeDef.DefCode); printf ("\n"); break; case IMPORT: printf (" import"); OutObject (&N->NodeData.NodeImp.ImpDef); printf ("\n"); break; default: printf (" invalid NodeType (%x)\n",N->NodeType); break; } } } #endif /* DUMP */ /*************************** end of debug.c *********************************/ SHAR_EOF if test -f 'interp/dos.s' then echo shar: over-writing existing file "'interp/dos.s'" fi cat << \SHAR_EOF > 'interp/dos.s' ; ;/****** dos.s**********************************************************/ ;/** **/ ;/** 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 28, 1985 **/ ;/** **/ ;/** Principal Investigators: Prof. R. H. Campbell **/ ;/** Prof. W. J. Kubitz **/ ;/** **/ ;/** **/ ;/**------------------------------------------------------------------**/ ;/** (C) Copyright 1987 University of Illinois Board of Trustees **/ ;/** All Rights Reserved. **/ ;/**********************************************************************/ ;/***** Assembly Language Routines for MS-DOS Implementation of IFP *****/ TITLE dos PUBLIC _StackCheck, _SetCBrk EXTRN __chkstk:FAR DOS_TEXT SEGMENT BYTE PUBLIC 'CODE' ASSUME CS: DOS_TEXT ; ; SetCBrk ; ; Set control-C trapping for any DOS call. ; _SetCBrk PROC FAR mov ax,3301H mov dl,01H int 21H ret _SetCBrk ENDP ; ; StackCheck ; ; Check if there is enough room on the stack and check for break signal ; _StackCheck PROC FAR push bp mov bp,sp mov ax,64H call FAR PTR __chkstk push es mov ah,2FH int 21H ; Dummy GET_DTA to look for control-C pop es mov sp,bp pop bp ret _StackCheck ENDP DOS_TEXT ENDS END ;/************************** end of dos.s **************************/ SHAR_EOF if test -f 'interp/error.c' then echo shar: over-writing existing file "'interp/error.c'" fi cat << \SHAR_EOF > 'interp/error.c' /****** error.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: Sept 8, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ /************************ Error Message Routines **********************/ #include <stdio.h> #include <ctype.h> #include "struct.h" #include "node.h" #include "umax.h" #include "inob.h" /* Some common error messages */ char ArgNotSeq[] = "not a sequence", ArgSeqOb [] = "must be <sequence object>", ArgObSeq [] = "must be <object sequence>", ArgNull [] = "empty sequence", ArgBottom[] = "argument is ?"; /* * PrintErr * * Check if error message should be printed. Error messages are not printed if * the argument is BOTTOM (in which case the error has already been noted), or * SysStop is set (the user has interrupted execution). * * Input * InOut = argument to function * * Output * result = true iff error message should be printed */ boolean PrintErr (InOut) ObjectPtr InOut; { return InOut->Tag != BOTTOM && !SysStop; } /* * FormError * * Print PFO error message. * * Input * InOut = input to form * Message = error message * N = offended form's index in FormTable * P = form parameter list */ void FormError (InOut,Message,N,P) ObjectPtr InOut; char *Message; int N; ListPtr P; { extern int TraceDepth; if (PrintErr (InOut)) { LineWait (); OutForm (FormTable[N].FormNode,P,TraceDepth); printf (": %s\n",Message); OutObject (InOut); printf ("\n"); LineSignal (); } RepTag (InOut,BOTTOM); } /* * FunError * * Print primitive function error. * * Input * Message = error message * InOut = offending object * ApplyFun {global} = offended function */ void FunError (Message,InOut) char *Message; ObjectPtr InOut; { if (PrintErr (InOut)) { LineWait (); printf ("\n"); OutNode (ApplyFun); printf (": %s\n",Message); OutObject (InOut); printf ("\n"); LineSignal (); } RepTag (InOut,BOTTOM); } /* * DefError * * Print definition error display. * * Input * Caller = calling node * F = name of erroneous function * Message = error message to print */ void DefError (Caller,F,Message) NodePtr Caller; ObjectPtr F; char *Message; { LineWait (); OutObject (F); if (Caller != NULL) { printf (" (from "); OutNode (Caller); printf (")"); } printf (": %s\n",Message); LineSignal (); } /* * IntError * * Print internal error message. * * Input * Message = error message */ void IntError (Message) char *Message; { fprintf (stderr,"\nINTERNAL ERROR (%s)\n",Message); if (Debug) abort (); SysError = INTERNAL; } /* * InError * * Print input error message. * * Input * F = input descriptor * Message = error message * * Output * result = 0 */ int InError (F,Message) InDesc *F; char *Message; { char *S; if (F->ComLevel > 0) Message = "open comment"; printf ("Input error"); if (F->InLineNum >= 0) { printf (" in "); OutNode (F->InDefMod); printf ("/"); if (F->InDefFun != NULL) OutString (F->InDefFun); else printf ("%IMPORT"); printf (" on line %d:\n%s",F->InLineNum,F->InBuf); if (F->InBuf[strlen (F->InBuf)-1] != '\n') printf ("\n"); } else printf ("\n"); for (S=F->InBuf; S<F->InPtr; S++) printf ("%c", isspace (*S) ? *S : ' '); printf ("^\n%s\n",Message); return F->ComLevel = 0; } /****************************** end of error.c *******************************/ SHAR_EOF if test -f 'interp/except.c' then echo shar: over-writing existing file "'interp/except.c'" fi cat << \SHAR_EOF > 'interp/except.c' /****** except.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: Dec 5, 1985 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ /************************* Exception Handlers *************************/ #include <stdio.h> #include "struct.h" #include "umax.h" #if OPSYS!=CTSS #include <signal.h> #endif /* * There are currently two exceptions which must be dealt with. * * 1. Interpreter (system) errors, e.g. out of memory * These are indicated by setting the variable 'SysError' to the * appropriate non-zero value. The values are listed in struct.h * * 2. User interrupts, i.e. ctrl-C. * These are counted by the variable SysStop. * * 0 = process normally * 1 = stop processing and print back trace * 2 = return to top level without printing back trace */ short SysError = 0; /* An error occurred if SysError != 0 */ short SysStop = 0; #if OPSYS!=CTSS private int SetStop () { SysStop++; (void) signal (SIGINT,SetStop); } #endif OPSYS!=CTSS /* * ResetExcept * * Reset exception handling to normal state. */ void ResetExcept () { extern int UDump(); SysError = 0; SysStop = 0; #if OPSYS!=CTSS (void) signal (SIGINT,SetStop); #endif #if OPSYS==DOS SetCBrk (); #endif } SHAR_EOF if test -f 'interp/file.c' then echo shar: over-writing existing file "'interp/file.c'" fi cat << \SHAR_EOF > 'interp/file.c' /****** file.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: June 22, 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 "string.h" #include "node.h" #include "umax.h" #include "inob.h" extern char *strcpy (),*strcat (),*getenv (); /*------------------------- Operating System Constants --------------------* * * Operating System Constants * * PATH_SEPARATOR = separator used for file names * EDITOR = path to editor * EdCommand = IFP command to invoke EDITOR * * Even operating systems without hierarchical file systems must * define a PATH_SEPARATOR, which is used still used internally. * * In the case of CTSS, we also have a constant USER_PATH. This * a fictious path to the user's current directory. */ #if OPSYS==UNIX #define PATH_SEPARATOR '/' #define EDITOR "/bin/vi" char *EdCommand; #endif #if OPSYS==MSDOS #define PATH_SEPARATOR '\\' #define EDITOR "c:ed.exe" char *EdCommand = "ed"; char DirPath [MAXPATH+1] = "c:dir.exe"; #endif #if OPSYS==CTSS #define PATH_SEPARATOR '/' #define EDITOR "fred" char *EdCommand = "fred"; #define USER_PATH "/usr" #endif /*-------------------- end of Operating System Constants --------------------*/ char RootPath [MAXPATH+1] = ""; /* Path to IFP's root */ char EditorPath [MAXPATH+1] = EDITOR; /* value is default */ char FPprompt[16] = "ifp> "; /* value is default */ NodePtr CurWorkDir = NULL; /* Current working directory node */ /********************** Operating system file interface ***********************/ /* * PathTail * * Return the last component in a path name. * Returns pointer to "" if error occurs. */ private char *PathTail (Path) char *Path; { register char *T; if (*Path == PATH_SEPARATOR) Path++; while (*Path) { for (T = Path; *T++ != PATH_SEPARATOR; ) if (!*T) return Path; Path = T; } return Path; } /*------------------------------ fopen hacks ------------------------------ * * Both MSDOS and CTSS have problems with hierarchical file structure. * Thus we have to redefine the standard UNIX function "fopen" to allow * for these operating system's quirks. */ #if OPSYS==MSDOS /* * We try to keep track of the current directory in CWDCache so we can avoid * superfluous calls to chdir. Set the 0th character to '\0' to empty the * cache. */ char CWDCache [MAXPATH] = ""; /* * PathSplit * * Split a pathname into its directory and file parts. * Change directory to directory part. * * Input * PathName = pathname * * Output * NULL if error occurs, pointer to file name otherwise. */ char *PathSplit (PathName) /* also used by command.c */ char *PathName; { register char *S,*T; register int R; T = PathTail (PathName); if (T != &PathName [1]) { T[-1] = '\0'; S = PathName; /* Break string at path separator */ } else S = "\\"; if (strcmp (S,CWDCache)) { R = chdir (S); if (Debug & DebugFile) printf ("cache load: %d = ChDir (%s) for %s\n",R,S,T); (void) strcpy (CWDCache,S); } else { if (Debug & DebugFile) printf ("cache HIT!\n"); R = 0; } T[-1] = PATH_SEPARATOR; /* Replace path separator */ return R ? NULL : T; } /* * DOSfopen * * Works as =`fopen' should. The old Lattice C `fopen' would not take * pathnames. Even though the new compiler's will allow long names, * the fake fopen can take advantage of the current directory cache. */ private FILE *DOSfopen (FileName,Mode) char *FileName,*Mode; { char *T; return (T = PathSplit (FileName)) != NULL ? fopen (T,Mode) : NULL; } #define fopen DOSfopen #endif /* OPSYS==MSDOS */ #if OPSYS==CTSS /* * CTSSfopen * * Tries for fake a real fopen. CTSS does not support hierarchical file * structures, so CTSSfopen takes the tail of the path as the file name. */ private FILE *CTSSfopen (FileName,Mode) char *FileName,*Mode; { register char *T; if (Debug & DebugFile) printf ("CTSSfopen (%s,%s)\n",FileName,Mode); T = PathTail (FileName); if (T == &FileName[1]) return NULL; else { T[-1] = '\0'; if (strcmp (FileName,USER_PATH)) return NULL; else { if (Debug & DebugFile) printf ("fopen (%s,%s)\n",T,Mode); return fopen (T,Mode); } } } #define fopen CTSSfopen #endif /* OPSYS==CTSS */ /*---------------------------- end of fopen hacks ----------------------------*/ /* * FormNPath * * Create the pathname for a given node. * * Input * N = pointer to node * PathLim = pointer to end of PathName buffer * * Output * Pathname for node */ char *FormNPath (N,PathName,PathLim) register NodePtr N; char PathName[]; register char *PathLim; { CharPtr U; register char *T; if (N->NodeParent == NULL) { (void) strcpy (PathName,RootPath); return &PathName [strlen (PathName)]; } else { T = FormNPath (N->NodeParent,PathName,PathLim); if (T==NULL) return NULL; else { *T++ = PATH_SEPARATOR; CPInit (&U,&N->NodeName); (void) CPRead (&U,T,PathLim-T); #if OPSYS==UNIX T += strlen (T); #endif #if OPSYS==MSDOS || OPSYS==CTSS /* DOS and CTSS names limited to 8 characters */ { int L; if ((L = strlen (T)) > 8) L = 8; *(T += L) = '\0'; } #endif if (!CPRead (&U,T,PathLim-T)) return T; else return NULL; /* U should be empty */ } } } /* * FormPath * * Make UNIX or DOS pathname for node * * Input * N = node or path list * PathName = buffer to put pathname in. * PathLim = pointer to end of buffer * * Output * PathName = pathname if successful */ void FormPath (N,PathName,PathLim) register ObjectPtr N; char PathName[]; char *PathLim; { register char *T; CharPtr U; register ListPtr P; register int K; switch (N->Tag) { case LIST: (void) strcpy (PathName,RootPath); K = strlen (PathName); PathLim -= K; T = &PathName [K]; for (P = N->List; P!=NULL; P=P->Next) { if (P->Val.Tag != STRING) return; else { CPInit (&U,&P->Val.String); (void) CPRead (&U,T,PathLim-PathName); #if OPSYS==UNIX T += strlen (T); #endif #if OPSYS==MSDOS || OPSYS==CTSS /* DOS names are limited to 8 characters */ if ((K = strlen (T)) > 8) K = 8; *(T += K) = '\0'; #endif /* T should always be <= PathLim */ if (T >= PathLim) return; } } break; case NODE: (void) FormNPath (N->Node,PathName,PathLim); break; default: break; } } /* * ReadDef * * Read a definition node. The definition node tag must be BOTTOM upon entry * when running UMAX. * * Input * Caller = pointer to DEF node of caller * Fun = object with tag NODE. */ void ReadDef (Caller,Fun) NodePtr Caller; ObjectPtr Fun; { NodePtr N; char FileName[MAXPATH]; FILE *DefFile; InDesc F; int C; if (NULL == FormNPath (N=Fun->Node,FileName,&FileName[MAXPATH])) DefError (Caller,Fun,"invalid name for function"); else while (NULL != (DefFile = fopen (FileName,"r"))) { InitIn (&F,N->NodeParent,DefFile,0); C = InDef (&F,N->NodeName,&N->NodeData.NodeDef.DefCode); (void) fclose (F.InFile); if (C) goto exit; printf ("Do you wish to edit %s ? ",FileName + strlen (RootPath)); while (1) { for (C = getchar (); getchar ()!='\n';) continue; if (C == 'y') { ExecEdit (FileName); break; } if (C == 'n') goto exit; printf ("Respond with y or n\n"); } } exit:; } /* * ReadImport * * Read the import file for a module node. * * Input * M = pointer to module node */ void ReadImport (M) NodePtr M; { char *T; char FileName[MAXPATH]; FILE *ImpFile; InDesc F; if (NULL != (T = FormNPath (M,FileName,&FileName[MAXPATH]))) { *T++ = PATH_SEPARATOR; (void) strcpy (T,"%IMPORT"); if (NULL != (ImpFile = fopen (FileName,"r"))) { InitIn (&F,M,ImpFile,0); InImport (&F,M); (void) fclose (ImpFile); } } } #if OPSYS!=CTSS /* * EnvGet * * Get value for environment variable. * * Input * Key = enviroment variable name * Value = default value for variable * ValLim = length of Value buffer * * Output * Value = value of enviroment variable, or default if not found. */ void EnvGet (Key,Value,ValLim) char *Key,*Value; int ValLim; { char *V; V = getenv (Key); if (V != NULL) if (strlen (V) < ValLim) (void) strcpy (Value,V); else fprintf (stderr,"Error: %s in enviroment is longer than %d\n", Key,MAXPATH-3); } /* * CWDGet * * Find pathname of current working directory (relative to FP root). * * Input * PathLim = length of Path buffer (used by PCAT versions only) * * Output * result = 1 if valid FP path, 0 otherwise * Path = FP pathname if valid, undefined otherwise */ boolean CWDGet (Path,PathLim) register char *Path; int PathLim; { #ifdef PCAT extern char *getcwd (); if (!getcwd (Path,PathLim-2)) return 0; #else #if S9000 extern FILE *popen (); FILE *F; /* S9000 Xenix has no getwd! */ F = popen ("/bin/pwd","r"); fscanf (F,"%s",Path); pclose (F); #else extern char *getwd(); if (!getwd (Path)) return 0; #endif /* S9000 */ #endif /* PCAT */ #if OPSYS==MSDOS (void) strcpy (Path,Path+2); /* Delete drive name */ if (Debug & DebugFile) printf ("CWD = '%s'\n",Path); return 1; #endif #if OPSYS==UNIX { register int K; K = strlen (RootPath); if (strncmp (Path,RootPath,K)) return 0; else { (void) strcpy (Path,&Path[K]); /* Remove FP root path prefix */ return 1; } } #endif } #endif /* OPSYS != CTSS */ /* * InitFile * * The DOS version is kludgy. The problem is that DOSfopen changes * the current directory, thus munging it before CWDGet is called. */ #if OPSYS==UNIX || OPSYS==CTSS void InitFile () #endif #if OPSYS==MSDOS void InitFile (CWD) char *CWD; #endif { Object X; InDesc F; if (Debug & DebugFile) printf ("enter InitFile\n"); #if OPSYS!=CTSS EnvGet ("EDITOR",EditorPath,MAXPATH); #endif if (Debug & DebugFile) printf ("EditorPath = `%s'\n",EditorPath); #if OPSYS==UNIX EdCommand = PathTail (EditorPath); if (!*EdCommand) { fprintf (stderr,"\n * EDITOR environment variable not a full path."); fprintf (stderr,"\n Setting editor to '%s'.\n",EDITOR); EdCommand = PathTail (strcpy (EditorPath,EDITOR)); } EnvGet ("IFPprompt",FPprompt,sizeof (FPprompt)); #endif #if OPSYS==MSDOS EnvGet ("IFPDIR",DirPath,MAXPATH); if (Debug & DebugFile) printf ("IFPDIR = '%s'\n",DirPath); #endif /* Create dummy descriptor for scanning environment info */ InitIn (&F,(NodePtr) NULL,(FILE *) NULL, -1); #if OPSYS==UNIX if (!CWDGet (F.InBuf,INBUFSIZE-1)) { fprintf (stderr,"\n\n * Current directory not a IFP subdirectory."); fprintf (stderr, "\n Setting current directory to IFP root.\n"); if (chdir (RootPath)) { extern int errno; perror (RootPath); exit (errno); } else F.InBuf[0] = '\0'; } #endif #if OPSYS==MSDOS { register char *T; (void) strcpy (F.InBuf,CWD); for (T=F.InBuf; *T; T++) if (*T == PATH_SEPARATOR) *T = '/'; } #endif #if OPSYS==CTSS (void) strcpy (F.InBuf,USER_PATH); #endif if (F.InBuf[0]) { (void) strcat (F.InPtr,"\n"); (void) InNode (&F,&X,NIL); CurWorkDir = MakeNode (X.List,1); } else CurWorkDir = RootNode; if (Debug & DebugFile) printf ("exit InitFile\n"); } /************************* end of file.c *******************************/ SHAR_EOF if test -f 'interp/forms.c' then echo shar: over-writing existing file "'interp/forms.c'" fi cat << \SHAR_EOF > 'interp/forms.c' /****** forms.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: July 28, 1986 **/ /** **/ /** Principal Investigators: Prof. R. H. Campbell **/ /** Prof. W. J. Kubitz **/ /** **/ /** **/ /**------------------------------------------------------------------**/ /** (C) Copyright 1987 University of Illinois Board of Trustees **/ /** All Rights Reserved. **/ /**********************************************************************/ #include "struct.h" #include "node.h" #include "umax.h" #include "stats.h" #include <stdio.h> /* * FF_Each * * Apply function F to each element of list InOut * * Input * InOut = list of elements to apply function * Funs = singleton list of function to be applied * * Output * InOut = result */ private FF_Each (InOut,Funs) ObjectPtr InOut; register ListPtr Funs; { register ListPtr P; switch (InOut->Tag) { default: FormError (InOut,ArgNotSeq,NODE_Each,Funs); return; case LIST: CopyTop (&InOut->List); break; } for (P = InOut->List; P!=NULL; P=P->Next) { Apply (&P->Val,&Funs->Val); if (P->Val.Tag == BOTTOM) { RepTag (InOut,BOTTOM); /* Error already reported */ return; } } } /* * FF_Filter * * Input * InOut = list of elements to apply predicate * Funs = singleton list of function to be applied * * Output * InOut = result - list of element for which predicate is true. */ private FF_Filter (InOut,Funs) register ObjectPtr InOut; register ListPtr Funs; { register ListPtr P; register MetaPtr E; ListPtr Result; Object X; if (InOut->Tag != LIST) FormError (InOut,ArgNotSeq,NODE_Filter,Funs); else { Result = NULL; E = &Result; for (P = InOut->List; P!=NULL; P=P->Next) { CopyObject (&X,&P->Val); Apply (&X,&Funs->Val); if (X.Tag != BOOLEAN) { FormError (&X,"non-boolean predicate",NODE_Filter,Funs); RepTag (InOut,BOTTOM); DelLPtr (Result); return; } else if (X.Bool) { /* append element to result list */ NewList (E,1L); CopyObject (&(*E)->Val,&P->Val); E = &(*E)->Next; } } DelLPtr (InOut->List); InOut->List = Result; } } /* * FF_Compose * * Function composition * * Input * InOut = object to apply composition * Funs = list of functions to compose in reverse order * * Output * InOut = result of composition */ private FF_Compose (InOut,Funs) register ObjectPtr InOut; register ListPtr Funs; { for (; Funs != NULL && InOut->Tag != BOTTOM; Funs = Funs->Next) Apply (InOut,&Funs->Val); } /* * FF_RInsert * * Function right insert */ private FF_RInsert (InOut,Funs) register ObjectPtr InOut; register ListPtr Funs; { ListPtr Terms; if (InOut->Tag != LIST) FormError (InOut,ArgNotSeq,NODE_RInsert,Funs); else if (InOut->List == NULL) FormError (InOut,"empty sequence",NODE_RInsert,Funs); else { F_Reverse (InOut); /* Copy top and reverse */ Terms = InOut->List->Next; InOut->List->Next = NULL; RepObject (InOut,&InOut->List->Val); while (Terms != NULL) { /* form pair and apply function */ NewList (&Terms->Next,1L); Terms->Next->Val.Tag = InOut->Tag; Terms->Next->Val.Data = InOut->Data; InOut->Tag = LIST; InOut->List = NULL; Rot3 (&InOut->List,&Terms,&Terms->Next->Next); Apply (InOut,&Funs->Val); if (InOut->Tag == BOTTOM) { DelLPtr (Terms); break; } } } } /* * FF_C * * Constant function */ private FF_C (InOut,Funs) ObjectPtr InOut; register ListPtr Funs; { Stat (StatConstant (InOut)); if (Funs == NULL) FormError (InOut,"(constant bottom)",NODE_C,Funs); else RepObject (InOut,&Funs->Val); } /* * FF_Out * * Print debugging message */ private FF_Out (InOut,Funs) ObjectPtr InOut; register ListPtr Funs; { LineWait (); OutObject (&Funs->Val), printf (": "), OutObject (InOut), printf ("\n"); LineSignal (); } #if FETCH /* * FF_Fetch * * Fetch form */ private FF_Fetch (InOut,Funs) ObjectPtr InOut; register ListPtr Funs; { register ListPtr P,Q,R; if (InOut->Tag != LIST) FormError (InOut,ArgNotSeq,NODE_Fetch,Funs); else { R = NULL; for (P = InOut->List; P != NULL; P=P->Next) if (P->Val.Tag != LIST || (Q=P->Val.List) == NULL || Q->Next == NULL || Q->Next->Next != NULL) { FormError (InOut,"element not a pair",NODE_Fetch,Funs); return; } else if (R == NULL && ObEqual (&Q->Val,&Funs->Val)) R = Q; if (R!=NULL) RepObject (InOut,&R->Next->Val); else FormError (InOut,"key not found",NODE_Fetch,Funs); return; } } #endif FETCH /* * FF_If * * Conditional p->f;g * * Input * InOut = object to apply conditional * Funs = <p f g> * * Output * InOut = result of conditional */ private FF_If (InOut,Funs) ObjectPtr InOut; ListPtr Funs; { Object P; CopyObject (&P,InOut); Apply (&P,&Funs->Val); if (P.Tag == BOOLEAN) Apply (InOut, & (P.Bool ? Funs : Funs->Next)->Next->Val); else { FormError (&P,"non-boolean predicate",NODE_If,Funs); RepTag (InOut,BOTTOM); } } /* * FF_Construct * * Function construction * * Input * InOut = object to apply construction * Funs = list of functions to construct * * Output * InOut = result */ private FF_Construct (InOut,Funs) register ObjectPtr InOut; ListPtr Funs; { register ListPtr P,F; Stat (StatConstruct (Funs)); P = Repeat (InOut, ListLength (F = Funs)); if (SysError) return; RepTag (InOut,LIST); for (InOut->List = P; F != NULL; P=P->Next,F=F->Next) { Apply (& P->Val,& F->Val); if (P->Val.Tag == BOTTOM) { RepTag (InOut,BOTTOM); /* Error was already reported */ return; } } } /* * FF_Select * * Selector form (e.g. 1,2r) * * Input * InOut = object * Funs = index parameter list - positive values are left selectors * negative values are right selectors */ private FF_Select (InOut,Funs) ObjectPtr InOut; ListPtr Funs; { register ListPtr P; register long N; char *E; N = Funs->Val.Int; switch (InOut->Tag) { default: E = ArgNotSeq; break; case NODE: NodeExpand (InOut); case LIST: P = InOut->List; if (N < 0) N += ListLength (P) + 1; if (--N >= 0) { for (; P!=NULL; P=P->Next) if (--N < 0) { RepObject (InOut,&P->Val); return; } E = "index off right end"; } else E = "index off left end"; break; } FormError (InOut,E,NODE_Sel,Funs); } /* * FF_While * * While P is true, apply F to X * * Input * InOut = X * Funs = pair <P F> * * Output * InOut = result */ private FF_While (InOut,Funs) register ObjectPtr InOut; register ListPtr Funs; { Object P; P.Tag = BOTTOM; while (InOut->Tag!=BOTTOM) { CopyObject (&P,InOut); /* old P was element of {?,f,t} */ Apply (&P,&Funs->Val); if (P.Tag != BOOLEAN) { FormError (&P,"non-boolean predicate",NODE_While,Funs); RepTag (InOut,BOTTOM); } else if (P.Bool) Apply (InOut,&Funs->Next->Val); else break; } } #if XDEF extern FF_XDef(); #endif /* * FormTable * * These entries must be ordered to correspond with the #defines in "node.h". */ FormEntry FormTable[] = { {NULL, "#", {"constant" ,-1,FF_C }, "#c"}, {NULL, "", {"compose" ,-1,FF_Compose }, ""}, {NULL, "[", {"construct",-1,FF_Construct}, "[...]"}, {NULL, "EACH", {"each" , 1,FF_Each }, "EACH g END"}, #if FETCH {NULL, "^", {"fetch" , 1,FF_Fetch }, "^c"}, #endif {NULL, "FILTER", {"filter" , 1,FF_Filter }, "FILTER p END"}, {NULL, "IF", {"if" , 3,FF_If }, "IF p THEN g ELSE h END"}, {NULL, "INSERT", {"insertr" , 1,FF_RInsert }, "INSERT g END"}, {NULL, "@", {"out" , 1,FF_Out }, "@message"}, {NULL, "", {"select" , 1,FF_Select }, "digit"}, {NULL, "WHILE", {"while" , 2,FF_While }, "WHILE p DO g END"} #if XDEF ,{NULL, "{", {"xdef" , 3,FF_XDef }, "{...}"}, #endif }; void D_form () { FormEntry *N; for (N=FormTable; N<ArrayEnd (FormTable); N++) N->FormNode = PrimDef (N->FormOp.OpPtr, N->FormOp.OpName, SysNode, N->FormOp.OpParam); } /******************************* end of forms.c *******************************/ 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@uunet.uu.net