home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1991 Regents of the University of California */
-
- #ifndef lint
- static char SCCSid[] = "@(#)calfunc.c 2.5 10/2/92 LBL";
- #endif
-
- /*
- * calfunc.c - routines for calcomp using functions.
- *
- * The define BIGLIB pulls in a large number of the
- * available math routines.
- *
- * If VARIABLE is not defined, only library functions
- * can be accessed.
- *
- * 4/2/86
- */
-
- #include <stdio.h>
-
- #include <errno.h>
-
- #include <math.h>
-
- #include "calcomp.h"
-
- /* bits in argument flag (better be right!) */
- #define AFLAGSIZ (8*sizeof(unsigned long))
- #define ALISTSIZ 6 /* maximum saved argument list */
-
- typedef struct activation {
- char *name; /* function name */
- struct activation *prev; /* previous activation */
- double *ap; /* argument list */
- unsigned long an; /* computed argument flags */
- EPNODE *fun; /* argument function */
- } ACTIVATION; /* an activation record */
-
- static ACTIVATION *curact = NULL;
-
- static double libfunc();
-
- #define MAXLIB 64 /* maximum number of library functions */
-
- static double l_if(), l_select(), l_rand();
- static double l_floor(), l_ceil();
- #ifdef BIGLIB
- static double l_sqrt();
- static double l_sin(), l_cos(), l_tan();
- static double l_asin(), l_acos(), l_atan(), l_atan2();
- static double l_exp(), l_log(), l_log10();
- #endif
-
- #ifdef BIGLIB
- /* functions must be listed alphabetically */
- static LIBR library[MAXLIB] = {
- { "acos", 1, ':', l_acos },
- { "asin", 1, ':', l_asin },
- { "atan", 1, ':', l_atan },
- { "atan2", 2, ':', l_atan2 },
- { "ceil", 1, ':', l_ceil },
- { "cos", 1, ':', l_cos },
- { "exp", 1, ':', l_exp },
- { "floor", 1, ':', l_floor },
- { "if", 3, ':', l_if },
- { "log", 1, ':', l_log },
- { "log10", 1, ':', l_log10 },
- { "rand", 1, ':', l_rand },
- { "select", 1, ':', l_select },
- { "sin", 1, ':', l_sin },
- { "sqrt", 1, ':', l_sqrt },
- { "tan", 1, ':', l_tan },
- };
-
- static int libsize = 16;
-
- #else
- /* functions must be listed alphabetically */
- static LIBR library[MAXLIB] = {
- { "ceil", 1, ':', l_ceil },
- { "floor", 1, ':', l_floor },
- { "if", 3, ':', l_if },
- { "rand", 1, ':', l_rand },
- { "select", 1, ':', l_select },
- };
-
- static int libsize = 5;
-
- #endif
-
- extern char *savestr(), *emalloc();
-
- extern VARDEF *argf();
-
- #ifdef VARIABLE
- #define resolve(ep) ((ep)->type==VAR?(ep)->v.ln:argf((ep)->v.chan))
- #else
- #define resolve(ep) ((ep)->v.ln)
- #define varlookup(name) NULL
- #endif
-
-
- int
- fundefined(fname) /* return # of arguments for function */
- char *fname;
- {
- LIBR *lp;
- register VARDEF *vp;
-
- if ((vp = varlookup(fname)) == NULL || vp->def == NULL
- || vp->def->v.kid->type != FUNC)
- if ((lp = liblookup(fname)) == NULL)
- return(0);
- else
- return(lp->nargs);
- else
- return(nekids(vp->def->v.kid) - 1);
- }
-
-
- double
- funvalue(fname, n, a) /* return a function value to the user */
- char *fname;
- int n;
- double *a;
- {
- ACTIVATION act;
- register VARDEF *vp;
- double rval;
- /* push environment */
- act.name = fname;
- act.prev = curact;
- act.ap = a;
- if (n >= AFLAGSIZ)
- act.an = ~0;
- else
- act.an = (1L<<n)-1;
- act.fun = NULL;
- curact = &act;
-
- if ((vp = varlookup(fname)) == NULL || vp->def == NULL
- || vp->def->v.kid->type != FUNC)
- rval = libfunc(fname, vp);
- else
- rval = evalue(vp->def->v.kid->sibling);
-
- curact = act.prev; /* pop environment */
- return(rval);
- }
-
-
- funset(fname, nargs, assign, fptr) /* set a library function */
- char *fname;
- int nargs;
- int assign;
- double (*fptr)();
- {
- register LIBR *lp;
-
- if ((lp = liblookup(fname)) == NULL) { /* insert */
- if (libsize >= MAXLIB) {
- eputs("Too many library functons!\n");
- quit(1);
- }
- for (lp = &library[libsize]; lp > library; lp--)
- if (strcmp(lp[-1].fname, fname) > 0) {
- lp[0].fname = lp[-1].fname;
- lp[0].nargs = lp[-1].nargs;
- lp[0].atyp = lp[-1].atyp;
- lp[0].f = lp[-1].f;
- } else
- break;
- libsize++;
- }
- if (fptr == NULL) { /* delete */
- while (lp < &library[libsize-1]) {
- lp[0].fname = lp[1].fname;
- lp[0].nargs = lp[1].nargs;
- lp[0].atyp = lp[1].atyp;
- lp[0].f = lp[1].f;
- lp++;
- }
- libsize--;
- } else { /* or assign */
- lp[0].fname = fname; /* string must be static! */
- lp[0].nargs = nargs;
- lp[0].atyp = assign;
- lp[0].f = fptr;
- }
- libupdate(fname); /* relink library */
- }
-
-
- int
- nargum() /* return number of available arguments */
- {
- register int n;
-
- if (curact == NULL)
- return(0);
- if (curact->fun == NULL) {
- for (n = 0; (1L<<n) & curact->an; n++)
- ;
- return(n);
- }
- return(nekids(curact->fun) - 1);
- }
-
-
- double
- argument(n) /* return nth argument for active function */
- register int n;
- {
- register ACTIVATION *actp = curact;
- register EPNODE *ep;
- double aval;
-
- if (actp == NULL || --n < 0) {
- eputs("Bad call to argument!\n");
- quit(1);
- }
- /* already computed? */
- if (n < AFLAGSIZ && 1L<<n & actp->an)
- return(actp->ap[n]);
-
- if (actp->fun == NULL || (ep = ekid(actp->fun, n+1)) == NULL) {
- eputs(actp->name);
- eputs(": too few arguments\n");
- quit(1);
- }
- curact = actp->prev; /* pop environment */
- aval = evalue(ep); /* compute argument */
- curact = actp; /* push back environment */
- if (n < ALISTSIZ) { /* save value */
- actp->ap[n] = aval;
- actp->an |= 1L<<n;
- }
- return(aval);
- }
-
-
- #ifdef VARIABLE
- VARDEF *
- argf(n) /* return function def for nth argument */
- int n;
- {
- register ACTIVATION *actp;
- register EPNODE *ep;
-
- for (actp = curact; actp != NULL; actp = actp->prev) {
-
- if (n <= 0)
- break;
-
- if (actp->fun == NULL)
- goto badarg;
-
- if ((ep = ekid(actp->fun, n)) == NULL) {
- eputs(actp->name);
- eputs(": too few arguments\n");
- quit(1);
- }
- if (ep->type == VAR)
- return(ep->v.ln); /* found it */
-
- if (ep->type != ARG)
- goto badarg;
-
- n = ep->v.chan; /* try previous context */
- }
- eputs("Bad call to argf!\n");
- quit(1);
-
- badarg:
- eputs(actp->name);
- eputs(": argument not a function\n");
- quit(1);
- }
-
-
- char *
- argfun(n) /* return function name for nth argument */
- int n;
- {
- return(argf(n)->name);
- }
- #endif
-
-
- double
- efunc(ep) /* evaluate a function */
- register EPNODE *ep;
- {
- ACTIVATION act;
- double alist[ALISTSIZ];
- double rval;
- register VARDEF *dp;
- /* push environment */
- dp = resolve(ep->v.kid);
- act.name = dp->name;
- act.prev = curact;
- act.ap = alist;
- act.an = 0;
- act.fun = ep;
- curact = &act;
-
- if (dp->def == NULL || dp->def->v.kid->type != FUNC)
- rval = libfunc(act.name, dp);
- else
- rval = evalue(dp->def->v.kid->sibling);
-
- curact = act.prev; /* pop environment */
- return(rval);
- }
-
-
- LIBR *
- liblookup(fname) /* look up a library function */
- char *fname;
- {
- int upper, lower;
- register int cm, i;
-
- lower = 0;
- upper = cm = libsize;
-
- while ((i = (lower + upper) >> 1) != cm) {
- cm = strcmp(fname, library[i].fname);
- if (cm > 0)
- lower = i;
- else if (cm < 0)
- upper = i;
- else
- return(&library[i]);
- cm = i;
- }
- return(NULL);
- }
-
-
- #ifndef VARIABLE
- static VARDEF *varlist = NULL; /* our list of dummy variables */
-
-
- VARDEF *
- varinsert(vname) /* dummy variable insert */
- char *vname;
- {
- register VARDEF *vp;
-
- vp = (VARDEF *)emalloc(sizeof(VARDEF));
- vp->name = savestr(vname);
- vp->nlinks = 1;
- vp->def = NULL;
- vp->lib = liblookup(vname);
- vp->next = varlist;
- varlist = vp;
- return(vp);
- }
-
-
- varfree(vp) /* free dummy variable */
- register VARDEF *vp;
- {
- register VARDEF *vp2;
-
- if (vp == varlist)
- varlist = vp->next;
- else {
- for (vp2 = varlist; vp2->next != vp; vp2 = vp2->next)
- ;
- vp2->next = vp->next;
- }
- freestr(vp->name);
- efree((char *)vp);
- }
-
-
- libupdate(nm) /* update library */
- char *nm;
- {
- register VARDEF *vp;
-
- for (vp = varlist; vp != NULL; vp = vp->next)
- vp->lib = liblookup(vp->name);
- }
- #endif
-
-
-
- /*
- * The following routines are for internal use:
- */
-
-
- static double
- libfunc(fname, vp) /* execute library function */
- char *fname;
- VARDEF *vp;
- {
- register LIBR *lp;
- double d;
- int lasterrno;
-
- if (vp != NULL)
- lp = vp->lib;
- else
- lp = liblookup(fname);
- if (lp == NULL) {
- eputs(fname);
- eputs(": undefined function\n");
- quit(1);
- }
- lasterrno = errno;
- errno = 0;
- d = (*lp->f)(lp->fname);
- #ifdef IEEE
- if (errno == 0)
- if (isnan(d))
- errno = EDOM;
- else if (isinf(d))
- errno = ERANGE;
- #endif
- if (errno) {
- wputs(fname);
- if (errno == EDOM)
- wputs(": domain error\n");
- else if (errno == ERANGE)
- wputs(": range error\n");
- else
- wputs(": error in call\n");
- return(0.0);
- }
- errno = lasterrno;
- return(d);
- }
-
-
- /*
- * Library functions:
- */
-
-
- static double
- l_if() /* if(cond, then, else) conditional expression */
- /* cond evaluates true if greater than zero */
- {
- if (argument(1) > 0.0)
- return(argument(2));
- else
- return(argument(3));
- }
-
-
- static double
- l_select() /* return argument #(A1+1) */
- {
- register int n;
-
- n = argument(1) + .5;
- if (n == 0)
- return(nargum()-1);
- if (n < 1 || n > nargum()-1) {
- errno = EDOM;
- return(0.0);
- }
- return(argument(n+1));
- }
-
-
- static double
- l_rand() /* random function between 0 and 1 */
- {
- double x;
-
- x = argument(1);
- x *= 1.0/(1.0 + x*x) + 2.71828182845904;
- x += .785398163397447 - floor(x);
- x = 1e5 / x;
- return(x - floor(x));
- }
-
-
- static double
- l_floor() /* return largest integer not greater than arg1 */
- {
- return(floor(argument(1)));
- }
-
-
- static double
- l_ceil() /* return smallest integer not less than arg1 */
- {
- return(ceil(argument(1)));
- }
-
-
- #ifdef BIGLIB
- static double
- l_sqrt()
- {
- return(sqrt(argument(1)));
- }
-
-
- static double
- l_sin()
- {
- return(sin(argument(1)));
- }
-
-
- static double
- l_cos()
- {
- return(cos(argument(1)));
- }
-
-
- static double
- l_tan()
- {
- return(tan(argument(1)));
- }
-
-
- static double
- l_asin()
- {
- return(asin(argument(1)));
- }
-
-
- static double
- l_acos()
- {
- return(acos(argument(1)));
- }
-
-
- static double
- l_atan()
- {
- return(atan(argument(1)));
- }
-
-
- static double
- l_atan2()
- {
- return(atan2(argument(1), argument(2)));
- }
-
-
- static double
- l_exp()
- {
- return(exp(argument(1)));
- }
-
-
- static double
- l_log()
- {
- return(log(argument(1)));
- }
-
-
- static double
- l_log10()
- {
- return(log10(argument(1)));
- }
- #endif
-