Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!uunet!rs
From: rs@uunet.UU.NET (Rich Salz)
Newsgroups: comp.sources.unix
Subject: v10i036: Interpreted Functional Programming lanuage, Part 03/07
Message-ID: <573@uunet.UU.NET>
Date: Tue, 7-Jul-87 00:32:09 EDT
Article-I.D.: uunet.573
Posted: Tue Jul 7 00:32:09 1987
Date-Received: Wed, 8-Jul-87 03:45:13 EDT
Organization: UUNET Communications Services, Arlington, VA
Lines: 2082
Approved: rs@uunet.uu.net
Mod.sources: Volume 10, Number 36
Submitted by: robison@b.cs.uiuc.edu (Arch Robison)
Archive-name: ifp/Part03
#! /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/F_arith.c
# interp/F_misc.c
# interp/F_pred.c
# interp/F_seq.c
# interp/F_ss.c
# interp/F_string.c
# interp/F_subseq.c
export PATH; PATH=/bin:$PATH
mkdir interp
if test -f 'interp/F_arith.c'
then
echo shar: over-writing existing file "'interp/F_arith.c'"
fi
cat << \SHAR_EOF > 'interp/F_arith.c'
/****** F_arith.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 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
#include
#include
#include "struct.h"
#include "node.h"
#if OPSYS!=CTSS
extern int errno; /* exists somewhere in UNIX */
#endif
/* NOTE - function Dyadic assumes integers are in two's complement form! */
private F_Minus (), F_AddN (), Monadic (), Dyadic (), F_Sum ();
private OpDef OpArith [] = {
#if OPSYS!=CTSS
{"ln", 0, Monadic},
{"exp", 1, Monadic},
{"sqrt", 2, Monadic},
{"sin", 3, Monadic},
{"cos", 4, Monadic},
{"tan", 5, Monadic},
{"arcsin", 6, Monadic},
{"arccos", 7, Monadic},
{"arctan", 8, Monadic},
#endif
{"minus", -1, F_Minus},
{"add1", 1, F_AddN},
{"sub1", -1, F_AddN},
{"+", 0, Dyadic},
{"-", 1, Dyadic},
{"*", 2, Dyadic},
{"%", 3, Dyadic},
#if OPSYS!=CTSS
{"mod", 4, Dyadic},
{"div", 5, Dyadic},
#endif
{"min", 6, Dyadic},
{"max", 7, Dyadic},
#if OPSYS!=CTSS
{"power", 8, Dyadic},
#endif
{"sum", -1, F_Sum}
};
/*
* Monadic
*
* Evaluate a monadic function
*
* Input
* InOut = argument to apply function
* Op = operation - see array F_Name in code for values
*
* Output
* InOut = result of applying function
*/
private Monadic (InOut,Op)
ObjectPtr InOut;
int Op;
{
double X,Z;
register int E;
if (GetDouble (InOut,&X)) FunError ("not numeric",InOut);
else {
E = 0;
switch (Op) {
#if OPSYS!=CTSS
case 0: /* base e log */
if (X <= 0) E = EDOM;
else Z = log (X);
break;
case 1: /* base e power */
if (X >= LNMAXFLOAT) E = ERANGE;
else Z = exp (X);
break;
case 2: /* square root */
if (X < 0) E = EDOM;
else Z = sqrt (X);
break;
case 3: /* sin */
Z = sin (X);
break;
case 4: /* cos */
Z = cos (X);
break;
case 5: /* tan */
Z = tan (X);
break;
case 6: /* arcsin */
Z = asin (X);
E = errno;
break;
case 7: /* arccos */
Z = acos (X);
E = errno;
break;
case 8: /* arctan */
Z = atan (X);
E = errno;
break;
#endif /* OPSYS!=CTSS */
case 9: /* minus */
Z = -X;
E = 0;
break;
}
switch (E) {
#if OPSYS!=CTSS
case EDOM:
FunError ("domain error",InOut);
break;
case ERANGE:
FunError ("range error",InOut);
break;
#endif
default:
InOut->Tag = FLOAT;
InOut->Float = Z;
break;
}
}
}
private F_Minus (InOut)
register ObjectPtr InOut;
{
if (InOut->Tag == INT && InOut->Int != FPMaxInt+1)
InOut->Int = - InOut->Int;
else Monadic (InOut,9);
}
/*
* F_Sum
*/
private F_Sum (InOut)
ObjectPtr InOut;
{
Object S;
register ListPtr P;
switch (InOut->Tag) {
default:
FunError (ArgNotSeq,InOut);
return;
case LIST:
S.Tag = INT;
S.Int = 0;
for (P=InOut->List; P!=NULL; P=P->Next) {
if (P->Val.Tag != INT && P->Val.Tag != FLOAT) {
FunError ("non-numeric sequence",InOut);
return;
}
if (S.Tag == INT) {
if (P->Val.Tag == INT) {
/* Both arguments are integers. See if we can avoid */
/* floating arithmetic. */
FPint Zi = S.Int + P->Val.Int;
if ((S.Int ^ P->Val.Int) < 0 || (S.Int^Zi))
/* arithmetic overflow occured - float result */;
else {
S.Int = Zi;
continue;
}
}
S.Float = S.Int;
S.Tag = FLOAT;
}
S.Float += P->Val.Tag==INT ? P->Val.Int : P->Val.Float;
}
break;
}
RepObject (InOut,&S);
}
/*
* Dyadic
*
* Evaluate a dyadic function
*
* Input
* InOut = argument to apply function
* Op = operation - see case statement in code for possibilities
*
* Output
* InOut = result of applying function
*
* The author sold his anti-GOTO morals for speed.
*/
private Dyadic (InOut,Op)
register ObjectPtr InOut;
register int Op;
{
double X,Y,Z;
register FPint Xi,Yi,Zi;
register ListPtr P,Q;
static char *DivZero = "division by zero";
if (InOut->Tag != LIST ||
NULL == (P=InOut->List) ||
NULL == (Q=P->Next) ||
Q->Next != NULL ||
NotNumPair (P->Val.Tag,Q->Val.Tag)) {
FunError ("not a numeric pair",InOut);
return;
}
if (IntPair (P->Val.Tag,Q->Val.Tag)) {
/* Both arguments are integers. See if we can avoid floating point */
/* arithmetic. */
Xi = P->Val.Int;
Yi = Q->Val.Int;
switch (Op) {
case 0:
/* assume two's complement arithmetic */
Zi = Xi+Yi;
if (((Xi ^ Yi) | ~(Xi ^ Zi)) < 0) goto RetInt;
break;
/* else arithmetic overflow occured */
case 1:
/* assume two's complement arithmetic */
Zi = Xi - Yi;
if (((Xi ^ Yi) & (Xi ^ Zi)) >= 0) goto RetInt;
/* else arithmetic overflow occured */
break;
case 2:
Zi = Xi * Yi;
if (Yi==0 || Zi/Yi == Xi) goto RetInt;
/* else arithmetic overflow occured */
break;
/* case 3: division result always FLOAT */
#if OPSYS!=CTSS
case 4: /* mod */
if (Xi >= 0 && Yi > 0) {
Zi = Xi % Yi;
goto RetInt;
}
break;
case 5: /* div */
if (Xi >= 0 && Yi > 0) {
Zi = Xi / Yi;
goto RetInt;
}
break;
#endif /* OPSYS!=CTSS */
case 6:
Zi = Xi > Yi ? Yi : Xi;
goto RetInt;
case 7:
Zi = Xi < Yi ? Yi : Xi;
goto RetInt;
/* case 8: power result always FLOAT */
}
}
X = P->Val.Tag==INT ? P->Val.Int : P->Val.Float;
Y = Q->Val.Tag==INT ? Q->Val.Int : Q->Val.Float;
switch (Op) {
case 0: Z = X + Y; break;
case 1: Z = X - Y; break;
case 2: Z = X * Y; break;
case 3:
if (Y==0.0) {
FunError (DivZero,InOut);
return;
}
Z = X / Y;
break;
#if OPSYS!=CTSS
case 4:
Z = Y==0.0 ? 0.0 : X - floor (X / Y) * Y; /* mod */
break;
case 5:
if (Y==0.0) { /* div */
FunError (DivZero,InOut);
return;
}
Z = floor (X / Y);
break;
#endif
case 6: Z = X > Y ? Y:X; break;
case 7: Z = X > Y ? X:Y; break;
#if OPSYS!=CTSS
case 8: Z = pow (X,Y); break;
#endif
}
InOut->Tag = FLOAT;
InOut->Float = Z;
Return:
DelLPtr (P);
return;
RetInt:
InOut->Tag = INT;
InOut->Int = Zi;
goto Return;
}
/*
* F_Add1
*/
private F_AddN (InOut,N)
register ObjectPtr InOut;
int N;
{
register FPint K;
switch (InOut->Tag) {
case INT:
K = InOut->Int + N;
if (N >= 0 ? InOut->Int <= K : InOut->Int > K) {
InOut->Int = K;
return;
}
/* else integer overflow - convert and drop down */
InOut->Float = ((FPfloat) InOut->Int);
InOut->Tag = FLOAT;
case FLOAT:
InOut->Float = InOut->Float + N;
break;
default:
FunError ("not a number",InOut);
break;
}
}
void D_arith ()
{
GroupDef (OpArith,OpCount (OpArith), ArithNode);
}
/************************** end of F_arith.c **************************/
SHAR_EOF
if test -f 'interp/F_misc.c'
then
echo shar: over-writing existing file "'interp/F_misc.c'"
fi
cat << \SHAR_EOF > 'interp/F_misc.c'
/****** F_misc.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 24, 1985 **/
/** **/
/** 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
#include "node.h"
#include "string.h"
/************************** miscellaneous functions *********************/
/*
* NodeExpand
*
* Replace object with equivalent object not containing nodes or bottoms.
*
* Nodes are converted to equivalent path lists.
* Bottoms are converted to "?".
*/
void NodeExpand (InOut)
register ObjectPtr InOut;
{
register ListPtr P;
register NodePtr N;
switch (InOut->Tag) {
case LIST:
CopyTop (&InOut->List);
for (P=InOut->List; P!=NULL; P=P->Next) NodeExpand (&P->Val);
break;
case NODE:
N = InOut->Node;
RepTag (InOut,LIST);
InOut->List = MakePath (N);
break;
}
}
/*
* F_Def
*
* Return the object representation of a function definition.
*
* Input
* *InOut = pathname list
*
* Output
* *InOut = function definition representation
*/
int F_Def (InOut) /* imported by Compile in C_comp.c */
register ObjectPtr InOut;
{
extern void ReadDef (), RepBool ();
register DefPtr D;
if (InOut->Tag != LIST) FunError (ArgNotSeq,InOut);
else {
LinkPath (InOut,DEF);
if (InOut->Tag==NODE && InOut->Node->NodeType==DEF) {
D = &InOut->Node->NodeData.NodeDef;
if (D->DefCode.Tag != CODE) {
if (D->DefCode.Tag == BOTTOM) ReadDef ((NodePtr) NULL,InOut);
if (D->DefCode.Tag != BOTTOM) {
RepObject (InOut,&D->DefCode);
NodeExpand (InOut);
return;
}
}
}
}
RepBool (InOut,0); /* function not defined */
}
/*
* F_Apply
*
* Apply a function to an object.
*
* Input
* InOut = where F is a function
*
* Output
* InOut = X : F
*/
private int F_Apply (InOut)
ObjectPtr InOut;
{
register ListPtr P;
/*
* We don't want to use PairTest test here, since it would expand
* the function if its a node. This would not affect the behavior
* at all, but would slow things down since the function must be
* converted to its node representation anyway.
*/
if (InOut->Tag != LIST || 2 != ListLength (InOut->List))
FunError ("not a pair",InOut);
else {
CopyTop (&InOut->List);
P = InOut->List;
if (ApplyCheck (&P->Next->Val)) {
Apply (&P->Val,&P->Next->Val);
RepObject (InOut,&P->Val);
} else
FunError ("invalid function",InOut);
}
}
void D_misc ()
{
(void) PrimDef (F_Apply,"apply",SysNode);
(void) PrimDef (F_Def,"def",SysNode);
}
/**************************** end of F_misc ****************************/
SHAR_EOF
if test -f 'interp/F_pred.c'
then
echo shar: over-writing existing file "'interp/F_pred.c'"
fi
cat << \SHAR_EOF > 'interp/F_pred.c'
/****** F_pred.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 1, 1985 **/
/** **/
/** Principal Investigators: Prof. R. H. Campbell **/
/** Prof. W. J. Kubitz **/
/** **/
/** **/
/**------------------------------------------------------------------**/
/** (C) Copyright 1987 University of Illinois Board of Trustees **/
/** All Rights Reserved. **/
/**********************************************************************/
#include
#include
#include "struct.h"
#include "node.h"
/************************** boolean functions **************************/
/*
* PairTest
*
* Check if object is a pair of
*
* Input
* X = object to test
* Mask1,Mask2 = masks representing type1 and type2 respectively.
* E.g 1<Tag != LIST)
if (X->Tag == NODE) NodeExpand (X);
else return 0;
if ((P=X->List) == NULL || (Q=P->Next) == NULL || Q->Next!=NULL) return 0;
if (P->Val.Tag == NODE) NodeExpand (&P->Val);
if (Q->Val.Tag == NODE) NodeExpand (&Q->Val);
return Mask1 >> P->Val.Tag & Mask2 >> Q->Val.Tag & 1;
}
/*
* Anytime two objects are found to be equal, we can replace one with
* the other to save memory. Clearly the memory savings is offset by
* a little more time, program complexity, and bringing obscure bugs
* out of the woodwork! Therefore the replacing action is enabled if
* MERGE=1, disabled if MERGE=0.
*
* P.S. Someone should check if the merging is really worth the cost.
*/
#define MERGE 0
/*
* BoolOp
*
* Boolean operation
*
* Input
* InOut = argument
* Op = boolean op (4-bit vector representing truth table)
*
* Output
* *A = first element of pair if result is true, undefined otherwise
* *B = second ...
*/
private BoolOp (InOut,Op)
ObjectPtr InOut;
int Op;
{
extern void RepBool ();
register ListPtr P;
if (PairTest (InOut,1<List;
RepBool (InOut, (Op >> (P->Next->Val.Bool << 1) + P->Val.Bool) & 1);
} else
FunError ("not a boolean pair",InOut);
}
/*
* F_Not
*
* Boolean negation
*/
private F_Not (InOut)
ObjectPtr InOut;
{
if (InOut->Tag == BOOLEAN) InOut->Bool ^= 1;
else FunError ("not boolean",InOut);
}
/*
* F_L2
*/
private F_L2 (InOut)
ObjectPtr InOut;
{
switch (InOut->Tag) {
case INT: RepBool (InOut,InOut->Int < 2); break;
case FLOAT: RepBool (InOut,InOut->Float < 2); break;
default: FunError ("not numeric",InOut); break;
}
}
/*
* F_False
*
* Check if argument is boolean false (#f).
*/
private F_False (InOut)
ObjectPtr InOut;
{
if (InOut->Tag == BOTTOM)
FunError (ArgBottom,InOut);
else
if (InOut->Tag == BOOLEAN) InOut->Bool ^= 1;
else RepBool (InOut,0);
}
/*
* F_Odd
*
* Check if integral argument is odd.
*/
private F_Odd (InOut)
ObjectPtr InOut;
{
FPint N;
switch (GetFPInt (InOut,&N)) {
case 0:
RepBool (InOut,(int)N & 1);
return;
case 2:
FunError ("not enough precision",InOut);
return;
default:
FunError ("not an integer",InOut);
return;
}
}
/*
* BoolSeq
*
* Evaluate "any" or "all" predicate.
*
* Input
* *InOut = argument
* Op = identity element of operation
*
* Output
* *InOut = result
*/
private BoolSeq (InOut,Op)
ObjectPtr InOut;
int Op;
{
register boolean R;
register ListPtr P;
if (InOut->Tag != LIST) FunError (ArgNotSeq,InOut);
else {
R = 0;
for (P = InOut->List; P != NULL; P=P->Next)
if (P->Val.Tag == BOOLEAN) R |= P->Val.Bool ^ Op;
else {
FunError ("non-boolean element",InOut);
return;
}
RepBool (InOut, R ^ Op);
}
}
#if MERGE
/*
* StrMerge
*
* Compare two strings. Merge together if they are equal.
*
* Output
* result = 1 if equal, 0 otherwise
*/
static int StrMerge (S,T)
register StrPtr *S,*T;
{
if (*S == *T) return 2; /* strings are identical */
else if (StrComp (*S,*T)) return 0; /* strings are different */
else {
register StrPtr *U; /* equal and not identical */
if ((*S)->SRef < (*T)->SRef)
U=S, S=T, T=U;
if ((*S)->SRef + 1) { /* S has larger SRef */
DelSPtr (*T);
*T = *S;
(*S)->SRef++;
}
return 1;
}
}
#endif
/*
* ObEqual
*
* Compare two objects. A comparison tolerance is used for floating point
* comparisons.
*
* Output
* result = 0 if objects are not equal
* 1 if objects are equal within comparison tolerance
*/
boolean ObEqual (X,Y)
ObjectPtr X,Y;
{
if (X->Tag != Y->Tag) {
switch (X->Tag) {
case INT:
return Y->Tag==FLOAT &&
!FloatComp ((double) X->Int,(double) Y->Float);
case FLOAT:
return Y->Tag==INT &&
!FloatComp ((double) X->Float,(double) Y->Int);
case NODE:
NodeExpand (X);
break;
case LIST:
if (Y->Tag==NODE) NodeExpand (Y);
break;
default: return 0;
}
}
switch (X->Tag) {
case BOTTOM: return 1;
case BOOLEAN: return X->Bool == Y->Bool;
case INT: return X->Int == Y->Int;
case FLOAT: return !FloatComp ((double) X->Float, (double) Y->Float);
case STRING:
#if MERGE
return StrMerge (&X->String,&Y->String);
#else
return !StrComp (X->String,Y->String);
#endif
case LIST: {
register ListPtr P=X->List, Q=Y->List;
while (1) {
if (P == NULL) return Q == NULL;
if (Q == NULL || !ObEqual (&P->Val,&Q->Val)) return 0;
P = P->Next; Q = Q->Next;
}
}
case NODE: return X->Node == Y->Node;
default: return 0; /* Tag error */
}
}
#define max(A,B) ((A) > (B) ? (A) : (B))
/*
* FloatComp
*
* X ~= Y if abs(X-Y) / max(abs(X),abs(Y)) <= comparison tolerance.
*
* Output
* result = -1 if X < Y
* 0 if X ~= Y
* 1 if X > Y
*/
int FloatComp (X,Y)
double X,Y;
{
double Xm,Ym,D;
Xm = fabs (X);
Ym = fabs (Y);
D = X-Y;
if (fabs (D) <= CompTol*max(Xm,Ym)) return 0;
else return D>0 ? 1 : -1;
}
/*
* F_Equal
*
* Object comparison for equality or inequality
*/
private F_Equal (InOut,Not)
ObjectPtr InOut;
int Not;
{
if (!PairTest (InOut,~0,~0))
FunError ("argument not a pair",InOut);
else
RepBool (InOut, Not ^ (0 < ObEqual (&InOut->List->Val,
&InOut->List->Next->Val)));
}
/*
* F_Null
*
* Null sequence test
*/
private F_Null (InOut)
ObjectPtr InOut;
{
switch (InOut->Tag) {
case LIST:
RepBool (InOut, InOut->List == NULL);
break;
default:
FunError (ArgNotSeq,InOut);
break;
}
}
/*
* F_Pair
*
* Check if argument is a pair.
*/
private F_Pair (InOut)
ObjectPtr InOut;
{
RepBool (InOut, PairTest (InOut,~0,~0));
}
/*
* F_Tag
*
* Check for specified tag
*/
private F_Tag (InOut,TagSet)
ObjectPtr InOut;
{
if (InOut->Tag)
RepBool (InOut,TagSet >> InOut->Tag & 1);
else
FunError (ArgBottom,InOut);
}
/*
* CompAtom
*
* Compare two atoms for <,<=,=>, or >
*
* Strings are ordered lexigraphically.
* Numbers are ordered in increasing value.
*
* Input
* *InOut =
* Op = comparison bit vector [>,=,<]
*
* Output
* *InOut = sign (X - Y) or BOTTOM
*/
private CompAtom (InOut,Op)
ObjectPtr InOut;
int Op;
{
register ObjectPtr X,Y;
int D,E;
static char *ErrMessage [3] = {
"not an atomic pair",
"booleans not comparable",
"strings and numbers not comparable"
};
E = 0;
if (!PairTest (InOut,ATOMIC,ATOMIC)) E = 1;
else {
X = &InOut->List->Val;
Y = &InOut->List->Next->Val;
if (X->Tag == BOOLEAN || Y->Tag == BOOLEAN) E = 2;
else if (X->Tag == STRING || Y->Tag == STRING) {
if (X->Tag != Y->Tag) E = 3;
else {
D = StrComp (X->String,Y->String);
if (D) D = (D>0) ? 1 : -1;
}
} else
if (X->Tag == INT)
if (Y->Tag == INT)
D = (X->Int > Y->Int) - (X->Int < Y->Int);
else
D = FloatComp ((double) X->Int,(double) Y->Float);
else
if (Y->Tag == INT)
D = FloatComp ((double) X->Float,(double) Y->Int);
else
D = FloatComp ((double) X->Float,(double) Y->Float);
}
if (E) FunError (ErrMessage [E-1],InOut);
else RepBool (InOut, (Op >> (D+1)) & 1);
}
/*
* CompLength
*
* Compare the length of two sequences.
*
* Input
* InOut = argument
* Shorter = if 0 then "longer" comparison, "shorter" otherwise.
*/
private CompLength (InOut,Shorter)
ObjectPtr InOut;
int Shorter;
{
register ListPtr P,Q;
if (!PairTest (InOut,1<List;
Q = P->Next->Val.List;
P = P->Val.List;
while (P != NULL && Q != NULL) {
P = P->Next;
Q = Q->Next;
}
RepBool (InOut, (Shorter ? Q : P) != NULL);
}
}
/*
* F_Member
*/
private F_Member (InOut)
ObjectPtr InOut;
{
register ListPtr P;
register ObjectPtr X;
if (! PairTest (InOut,1 << LIST,~0))
FunError (ArgSeqOb,InOut);
else {
P = InOut->List;
X = & P->Next->Val;
for (P = P->Val.List; P!=NULL; P=P->Next)
if (ObEqual (& P->Val,X)) break;
RepBool (InOut, P != NULL);
}
}
private OpDef LogicOps [] = {
{"all", 1, BoolSeq},
{"and", 0x8, BoolOp},
{"any", 0, BoolSeq},
{"atom", ATOMIC, F_Tag},
{"boolean", 1<", 0x4, CompAtom},
{"<", 0x1, CompAtom},
{">=", 0x6, CompAtom},
{"<=", 0x3, CompAtom},
{"l2", 0, F_L2}
};
void D_pred ()
{
GroupDef (LogicOps, OpCount (LogicOps), LogicNode);
}
/******************************* end of F_pred *******************************/
SHAR_EOF
if test -f 'interp/F_seq.c'
then
echo shar: over-writing existing file "'interp/F_seq.c'"
fi
cat << \SHAR_EOF > 'interp/F_seq.c'
/****** F_seq.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 5, 1986 **/
/** **/
/** Principal Investigators: Prof. R. H. Campbell **/
/** Prof. W. J. Kubitz **/
/** **/
/** **/
/**------------------------------------------------------------------**/
/** (C) Copyright 1987 University of Illinois Board of Trustees **/
/** All Rights Reserved. **/
/**********************************************************************/
/******************* sequence (structural) functions ******************/
#include
#include "struct.h"
#include "node.h"
/*
* F_Cat
*
* Sequence catenation
*/
private F_Cat (InOut)
register ObjectPtr InOut;
{
register MetaPtr E;
register ListPtr P;
if (InOut->Tag != LIST) {
FunError (ArgNotSeq,InOut);
return;
}
P = InOut->List;
if (P == NULL) return;
do
if (P->Val.Tag != LIST) {
FunError ("elements not sequences",InOut);
return;
}
while ((P=P->Next)!=NULL);
Copy2Top (& InOut->List);
if (SysError) return;
P = InOut->List;
E = &P->Val.List;
for (P=P->Next; P!=NULL; P=P->Next) {
while (*E!=NULL) E = &(*E)->Next;
*E = P->Val.List;
P->Val.Tag = BOTTOM;
}
E = &InOut->List;
RepLPtr (E,(*E)->Val.List);
}
/*
* F_Iota
*
* Generate <1...id>
*/
private F_Iota (InOut)
register ObjectPtr InOut;
{
FPint N;
register FPint K;
register ListPtr Pr;
switch (GetFPInt (InOut,&N)) {
case 1: FunError ("not an integer",InOut); return;
case 2: FunError ("too big" ,InOut); return;
case 0:
if (N < 0) FunError ("negative",InOut);
else {
InOut->Tag = LIST;
InOut->List = NULL;
NewList (&InOut->List,N);
if (SysError) return;
for (Pr=InOut->List,K=0; Pr!=NULL; Pr=Pr->Next)
Pr->Val.Tag = INT,
Pr->Val.Int = ++K;
}
return;
}
}
/*
* F_Id
*/
private F_Id ()
{
return; /* do nothing */;
}
/*
* F_Length
*
* Find sequence length
*/
private F_Length (InOut)
ObjectPtr InOut;
{
register FPint N;
switch (InOut->Tag) {
default:
FunError (ArgNotSeq,InOut);
return;
case LIST:
N = ListLength (InOut->List);
break;
}
RepTag (InOut,INT);
InOut->Int = N;
}
/*
* F_LApnd
*
* +--------+
* InOut --->| list |
* +----+---+ A
* | |
* V V
* +------------+ +------------+
* | object | o-+----->| list |///|
* +------------+ +---+--------+
* |
* V
* ...
*/
private F_LApnd (InOut)
ObjectPtr InOut;
{
MetaPtr A;
if (! PairTest (InOut, ~0, SEQUENCE))
FunError (ArgObSeq,InOut);
else {
CopyTop (&InOut->List);
A = & InOut->List->Next;
RepLPtr (A,(*A)->Val.List);
}
}
/*
* F_RApnd
*
* +--------+
* InOut --->| list |
* +----+---+
* |
* V
* +------------+ +------------+
* | list | o-+----->| object |///|
* +------------+ +------------+
* |
* V
* ...
*
*/
private F_RApnd (InOut)
ObjectPtr InOut;
{
register MetaPtr E;
ListPtr P;
if (! PairTest (InOut,1 << LIST,~0))
FunError (ArgSeqOb,InOut);
else {
Copy2Top (& InOut->List);
if (SysError) return;
P = InOut->List;
for (E = &P->Val.List; (*E)!=NULL; E = &(*E)->Next) continue;
*E = P->Next;
P->Next=NULL;
RepLPtr (&InOut->List,P->Val.List);
/* No system error possible since source is fresh list */
}
}
/*
* F_LDist
*
* Distribute from left
*/
private F_LDist (InOut)
ObjectPtr InOut;
{
ListPtr R=NULL;
register ListPtr P1,P2,P3,PT;
long N;
if (!PairTest (InOut, ~0, SEQUENCE))
FunError (ArgObSeq,InOut);
else {
Copy2Top (&InOut->List);
if (SysError) return;
P1 = InOut->List; /* P1 = pointer to arg list */
P2 = P1->Next;
P3 = P2->Val.List; /* P3 = pointer to 2nd arg list */
P2->Val.List = NULL;
N = ListLength (P3);
NewList (&R,N); /* R = pointer to result list */
if (SysError) return;
P2 = Repeat (&P1->Val,N); /* P2 = pointer to 1st arg list */
if (SysError) {DelLPtr (R); return;}
for (P1=R; P1!=NULL; P1=P1->Next) {
P1->Val.Tag = LIST;
P1->Val.List = P2;
PT = P2;
P2 = P2->Next;
PT->Next = P3;
PT = P3;
P3 = P3->Next;
PT->Next = NULL;
}
DelLPtr (InOut->List);
InOut->List = R;
}
}
/*
* F_RDist
*
* Distribute from right
*/
private F_RDist (InOut)
ObjectPtr InOut;
{
ListPtr R,P,P1,P2;
long N;
if (! PairTest (InOut, SEQUENCE, ~0))
FunError (ArgSeqOb,InOut);
else {
Copy2Top (&InOut->List);
if (SysError) return;
P = InOut->List; /* P = pointer to arg list */
P2 = P->Val.List; /* P2 = pointer to first arg list */
P->Val.Tag = BOTTOM;
P = P->Next; /* P = pointer to 2nd arg */
N = ListLength (P2);
R = NULL; NewList (&R,N); /* R = pointer to result list */
if (SysError) return;
for (P1=R; P1!=NULL; P1=P1->Next) {
P1->Val.Tag = LIST;
P1->Val.List = CopyLPtr (P);
if (SysError) {DelLPtr (R); return;}
Rot3 (&P1->Val.List,&P2,&P2->Next);
}
RepLPtr (&InOut->List,R);
DelLPtr (R);
}
}
/*
* F_Reverse
*
* Reverse a list
*/
F_Reverse (InOut) /* Imported by F_RInsert in forms.c */
ObjectPtr InOut;
{
ListPtr P,Q;
switch (InOut->Tag) {
default:
FunError (ArgNotSeq,InOut);
break;
case LIST:
P = InOut->List;
CopyTop (&P);
if (SysError) return;
for (Q=NULL; P!=NULL; Rot3 (&P,&P->Next,&Q)) continue;
InOut->List = Q;
break;
}
}
/*
* TransCheck
*
* Check that InOut is matrix
*
* Input
* InOut = pointer to object
*
* Output
* result = NULL iff a matrix, error code otherwise.
* *Cols = number of columns
*/
private char *TransCheck (InOut,Cols)
ObjectPtr InOut;
long *Cols;
{
register ListPtr V,VR;
if (InOut->Tag != LIST)
return "argument not a sequence.";
else if (NULL == (VR = InOut->List))
return "argument is empty sequence.";
else
for (V = VR; V !=NULL; V = V->Next)
if (V->Val.Tag != LIST)
return "argument subelements must be sequences.";
else if (V==VR) *Cols = ListLength (V->Val.List);
else if (*Cols != ListLength (V->Val.List))
return "argument not rectangular.";
else continue;
return NULL;
}
/*
* F_Trans
*
* Transpose a matrix (sequence of sequences)
*/
private F_Trans (InOut)
ObjectPtr InOut;
{
char *E; long Cols;
ListPtr VR,HR,H;
register ListPtr U,V;
register MetaPtr A;
/* Check for rectangularness */
if (NULL != (E = TransCheck (InOut,&Cols))) {
FunError (E,InOut);
return;
}
/* Make fresh copy of vertical top level and rows */
Copy2Top (&InOut->List);
if (SysError) return;
else VR = InOut->List;
/* Make horizontal top level */
HR = NULL;
NewList (&HR,Cols);
/* Transpose matrix column by column */
for (H=HR; H!=NULL; H=H->Next) {
H->Val.Tag = LIST;
H->Val.List = VR->Val.List;
/* Relink the column and advance the VR list to the next column */
for (V=VR; V!=NULL; V=U) {
U = V->Next;
A = &V->Val.List->Next;
V->Val.List = *A;
*A = U==NULL ? NULL : U->Val.List;
}
}
/* Delete the old vertical top level and return new matrix */
DelLPtr (VR); InOut->List = HR;
}
/*
* F_Tail
*/
private F_Tail (InOut)
ObjectPtr InOut;
{
register ListPtr P;
switch (InOut->Tag) {
default:
FunError (ArgNotSeq,InOut);
break;
case LIST:
if (NULL == (P = InOut->List)) FunError (ArgNull,InOut);
else RepLPtr (&InOut->List,P->Next);
break;
}
}
/*
* F_RTail
*
* Drop last element
*/
private F_RTail (InOut)
ObjectPtr InOut;
{
register MetaPtr A;
if (InOut->Tag != LIST)
FunError (ArgNotSeq,InOut);
else if (NULL == InOut->List)
FunError (ArgNull,InOut);
else {
CopyTop (A = &InOut->List);
if (SysError) return;
while ((*A)->Next != NULL) A = &(*A)->Next;
RepLPtr (A,(ListPtr) NULL);
}
}
OpDef SeqOps [] = {
{"apndl", -1, F_LApnd},
{"apndr", -1, F_RApnd},
{"cat", -1, F_Cat},
{"distl", -1, F_LDist},
{"distr", -1, F_RDist},
{"id", -1, F_Id},
{"iota", -1, F_Iota},
{"length", -1, F_Length},
{"reverse", -1, F_Reverse},
{"tl", -1, F_Tail},
{"tlr", -1, F_RTail},
{"trans", -1, F_Trans}
};
void D_seq ()
{
GroupDef (SeqOps, OpCount (SeqOps), SysNode);
}
/************************** end of F_seq **************************/
SHAR_EOF
if test -f 'interp/F_ss.c'
then
echo shar: over-writing existing file "'interp/F_ss.c'"
fi
cat << \SHAR_EOF > 'interp/F_ss.c'
/****** F_ss.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 4, 1985 **/
/** **/
/** Principal Investigators: Prof. R. H. Campbell **/
/** Prof. W. J. Kubitz **/
/** **/
/** **/
/**------------------------------------------------------------------**/
/** (C) Copyright 1987 University of Illinois Board of Trustees **/
/** All Rights Reserved. **/
/**********************************************************************/
#include
#include "struct.h"
#include "node.h"
/*************************** Searching and Sorting ***************************/
/*
* F_Assoc
*
* Just like LISP assoc, except that #f is returned if the key is not found.
*
* [association-list,key] | assoc == element of association list or #f
*/
private F_Assoc (InOut)
ObjectPtr InOut;
{
register ListPtr P;
register ObjectPtr Key;
if (!PairTest (InOut,1<List;
Key = &P->Next->Val;
for (P = P->Val.List; P != NULL; P=P->Next)
if (P->Val.Tag != LIST) {
FunError ("element not sequence",InOut);
return;
} else
if (ObEqual (&P->Val.List->Val,Key)) {
RepObject (InOut,&P->Val);
return;
}
RepBool (InOut,0); /* key not found, return #f */
}
}
void D_ss ()
{
(void) PrimDef (F_Assoc,"assoc",SysNode);
}
/******************************* end of F_ss.c *******************************/
SHAR_EOF
if test -f 'interp/F_string.c'
then
echo shar: over-writing existing file "'interp/F_string.c'"
fi
cat << \SHAR_EOF > 'interp/F_string.c'
/****** F_string.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 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
#include "struct.h"
#include "string.h"
#include "node.h"
/*
* F_Patom
*
* Convert an atom to it's string representation.
*/
private F_Patom (InOut)
register ObjectPtr InOut;
{
CharPtr U;
char Buf[255];
StrPtr S;
register char *T;
extern char *sprintf();
T = Buf;
switch (InOut->Tag) {
case INT:
(void) sprintf (T,"%d",InOut->Int);
break;
case FLOAT:
(void) sprintf (T,"%g",InOut->Float);
break;
case BOOLEAN:
(void) sprintf (T,InOut->Bool ? "t":"f");
break;
case STRING:
return;
default:
FunError ("not atomic",InOut);
return;
}
S = NULL;
CPInit (&U,&S);
do CPAppend (&U,*T); while (*T++);
RepTag (InOut,STRING);
InOut->String = S;
}
/*
* F_Explode
*
* Convert a string to a list of characters
*/
private F_Explode (InOut)
ObjectPtr InOut;
{
ListPtr Result = NULL;
MetaPtr A = &Result;
CharPtr U;
char C[2];
if (InOut->Tag != STRING)
FunError ("not a string",InOut);
else {
CPInit (&U,&InOut->String);
while (CPRead (&U,C,2)) {
NewList (A,1L);
if (SysError) {DelLPtr (Result); return;}
(*A)->Val.Tag = STRING;
(*A)->Val.String = CopySPtr (CharString [C[0] & 0x7F]);
A = &(*A)->Next;
}
RepTag (InOut,LIST);
InOut->List = Result;
}
}
/*
* F_Implode
*
* Catenate a list of strings into a single string.
*/
private F_Implode (InOut)
ObjectPtr InOut;
{
CharPtr U,V;
char C[2];
ListPtr P;
StrPtr S;
if (InOut->Tag != LIST)
FunError ("not a sequence",InOut);
else {
S = NULL;
CPInit (&U,&S);
for (P = InOut->List; P != NULL; P=P->Next) {
if (P->Val.Tag != STRING) {
FunError ("non-string in sequence",InOut);
CPAppend (&U,'\0');
DelSPtr (S);
return;
} else {
CPInit (&V,&P->Val.String);
while (CPRead (&V,C,2)) CPAppend (&U,C[0]);
}
}
CPAppend (&U,'\0');
RepTag (InOut,STRING);
InOut->String = S;
}
}
void D_string ()
{
(void) PrimDef (F_Explode,"explode",SysNode);
(void) PrimDef (F_Implode,"implode",SysNode);
(void) PrimDef (F_Patom,"patom",SysNode);
}
/************************** end of F_string **************************/
SHAR_EOF
if test -f 'interp/F_subseq.c'
then
echo shar: over-writing existing file "'interp/F_subseq.c'"
fi
cat << \SHAR_EOF > 'interp/F_subseq.c'
/****** F_subseq.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: Apr 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 /* defines NULL */
#include "struct.h"
#include "node.h"
/*
* ListIndex
*
* Check an argument to make sure it is of the form
*
* Input
* InOut = argument
*
* Output
* *L = sequence or array if no error
* result = -1 if error occurred, index otherwise
*/
private long ListIndex (InOut,L)
ObjectPtr InOut;
ListPtr *L;
{
register ListPtr P;
FPint N;
if (!PairTest (InOut, SEQUENCE, NUMERIC)) {
FunError ("not ",InOut);
return -1;
} else {
P = InOut->List;
*L = P->Val.List;
P = P->Next;
switch (GetFPInt (&P->Val,&N)) {
default: /* actually case 0, but we need to keep lint happy */
if (N >= 0) return N;
else {
FunError ("negative index",InOut);
return -1;
}
case 1:
FunError ("index not integral",InOut);
return -1;
case 2:
FunError ("index too big",InOut);
return -1;
}
}
}
#define SCATTER_STORE 0
#if SCATTER_STORE
/*
* F_Scatter
*
* Scatter store function
*
* Input
* < < ... >>
*
* Output
*
*
* Ek = Dk if there is no Ij == k
* Vj if Ij == k
*
* Result is BOTTOM if Ij==Ik for j!=k or Ij < 1 or Ij > n
*
* Perversions: uses LRef field for markers
*/
private F_Scatter (InOut)
ObjectPtr InOut;
{
register ListPtr P1,P2,Q,R;
register long N;
FPint M;
if (!PairTest (InOut,1<",InOut);
else {
Copy2Top (&InOut->List); /* only need fresh first element */
P1 = InOut->List;
R = P1->Val.List;
N = ListLength (R);
for (P1 = P1->Next->Val.List; P1!=NULL; P1=P1->Next) {
if (!PairTest (&P1->Val,~0,NUMERIC)) {
FunError ("invalid store pair",InOut);
return;
}
P2 = P1->Val.List;
if (GetFPInt (&P2->Next->Val,&M) || M < 1 || M > N) {
FunError ("invalid index",InOut);
return;
}
for (Q=R; --M; Q=Q->Next) continue;
if (++Q->LRef > 2) {
for (Q=R; Q!=NULL; Q=Q->Next) Q->LRef = 1;
FunError ("duplicate index",InOut);
return;
}
RepObject (&Q->Val,&P2->Val);
}
for (Q=R; Q!=NULL; Q=Q->Next) Q->LRef = 1;
RepObject (InOut,&InOut->List->Val);
}
}
#endif
/*
* F_Pick
*
* Pick the nth element of a sequence
*
* Input
* InOut = pointer to
*/
private F_Pick (InOut)
ObjectPtr InOut;
{
register FPint N;
ListPtr P;
if ((N = ListIndex (InOut,&P)) >= 0) {
if (N <= 0) {
FunError ("non-positive index",InOut);
} else if (P == NULL) FunError ("empty sequence",InOut);
else {
while (--N > 0)
if ((P = P->Next) == NULL) {
FunError ("index out of bounds",InOut);
return;
}
RepObject (InOut,&P->Val);
}
}
}
/*
* F_Repeat
*
* Create a repetition of an item.
*
* E.g. ==
*/
private F_Repeat (InOut)
register ObjectPtr InOut;
{
FPint N;
register ListPtr P;
if (!PairTest (InOut,~0,NUMERIC))
FunError ("not