home *** CD-ROM | disk | FTP | other *** search
- /* :ts=8 */
- /* Copyright (c) 1986 Regents of the University of California */
-
- #include <stdio.h>
- #include <errno.h>
-
- #include "calcomp.h"
- #include "calc.h"
-
-
- #define ALISTSIZ 6 /* maximum saved argument list */
-
- typedef struct Activation_Tag {
- char *Function_Name; /* function name */
- struct Activation_Tag *Prev_Act; /* previous activation */
- double *ArgTab; /* argument list */
- unsigned long ArgFlags; /* computed argument flags */
- Expression_T *Function; /* argument function */
- } Activation_T; /* an activation record */
-
- static Activation_T *Current_Act = NULL;
-
- static double Func_Exec();
-
- #define MAXLIB 64 /* maximum number of library functions */
-
- static double l_if(), l_select(), l_rand();
- static double l_floor(), l_ceil();
- 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();
- static double l_bezier(), l_bspline();
-
- double l_noise3(), l_noise3a(), l_noise3b(), l_noise3c();
- double l_hermite(), l_fnoise3();
-
- /* functions must be listed alphabetically */
- static Function_T LibFuncs[MAXLIB] = {
- { "acos", 1, ':', l_acos },
- { "asin", 1, ':', l_asin },
- { "atan", 1, ':', l_atan },
- { "atan2", 2, ':', l_atan2 },
- { "bezier", 5, ':', l_bezier },
- { "bspline", 5, ':', l_bspline },
- { "ceil", 1, ':', l_ceil },
- { "cos", 1, ':', l_cos },
- { "exp", 1, ':', l_exp },
- { "floor", 1, ':', l_floor },
- { "fnoise3", 3, ':', l_fnoise3 },
- { "hermite", 5, ':', l_hermite },
- { "if", 3, ':', l_if },
- { "log", 1, ':', l_log },
- { "log10", 1, ':', l_log10 },
- { "noise3", 3, ':', l_noise3 },
- { "noise3a", 3, ':', l_noise3a },
- { "noise3b", 3, ':', l_noise3b },
- { "noise3c", 3, ':', l_noise3c },
- { "rand", 1, ':', l_rand },
- { "select", 1, ':', l_select },
- { "sin", 1, ':', l_sin },
- { "sqrt", 1, ':', l_sqrt },
- { "tan", 1, ':', l_tan },
- };
-
-
- static int Nbr_LibFuncs = 24;
-
- extern char *savestr(), *Emalloc();
-
- extern Function_T *LibFunc_Lookup();
-
- extern Variable_T *Get_Func_Arg();
-
- #define Resolve(Expr) ( (Expr)->Node_Type == ET_Variable ? \
- (Expr)->Value.Variable : Get_Func_Arg((Expr)->Value.Channel) )
-
-
- int Func_Nbr_Args(Function_Name)
- char *Function_Name;
- /************************************************************************/
- /* */
- /* return # of arguments for function */
- /* */
- /************************************************************************/
- {
- Function_T *lp;
- register Variable_T *vp;
-
- if ((vp = Var_Lookup(Function_Name)) == NULL ||
- vp->Expression == NULL ||
- vp->Expression->Value.Kid->Node_Type != ET_Function) {
-
- if ((lp = LibFunc_Lookup(Function_Name)) == NULL) return(0);
- else return( (int) lp->Number_Args);
-
- } else return(Nbr_Kids(vp->Expression->Value.Kid) - 1);
-
- } /* Func_Nbr_Args */
-
-
- double Func_Value(Function_Name, n, ArgTab)
- char *Function_Name;
- int n;
- double *ArgTab;
- /************************************************************************/
- /* */
- /* return a function value to the user */
- /* */
- /************************************************************************/
- {
- Activation_T Activation_Record;
- register Variable_T *vp;
- double rval;
- /* push environment */
- Activation_Record.Function_Name = Function_Name;
- Activation_Record.Prev_Act = Current_Act;
- Activation_Record.ArgTab = ArgTab;
- Activation_Record.ArgFlags = (1L<<n)-1;
- Activation_Record.Function = NULL;
-
- Current_Act = &Activation_Record;
-
- if ((vp = Var_Lookup(Function_Name)) == NULL ||
- vp->Expression == NULL ||
- vp->Expression->Value.Kid->Node_Type != ET_Function) {
-
- rval = Func_Exec(Function_Name, vp);
-
- } else {
-
- rval = Expr_Value(vp->Expression->Value.Kid->Sibling);
-
- }
-
- Current_Act = Activation_Record.Prev_Act; /* pop environment */
-
- return(rval);
-
- } /* Func_Value */
-
-
- void Func_Set(Function_Name, Number_Args, Assignment_Type, Func_Ptr)
- char *Function_Name;
- int Number_Args;
- int Assignment_Type;
- double (*Func_Ptr)();
- /************************************************************************/
- /* */
- /* set a library function */
- /* */
- /************************************************************************/
- {
- register Function_T *Fp;
-
- if ((Fp = LibFunc_Lookup(Function_Name)) == NULL) {
-
- if (Nbr_LibFuncs >= MAXLIB) {
-
- fprintf(stderr, "Too many library functions!\n");
- exit(1);
-
- }
-
- for (Fp = &LibFuncs[Nbr_LibFuncs]; Fp > LibFuncs; Fp--)
-
- if (strcmp(Fp[-1].Function_Name, Function_Name) > 0) {
-
- Fp[0].Function_Name = Fp[-1].Function_Name;
- Fp[0].Number_Args = Fp[-1].Number_Args;
- Fp[0].Assignment_Type = Fp[-1].Assignment_Type;
- Fp[0].Func_Ptr = Fp[-1].Func_Ptr;
-
- } else break;
-
- Nbr_LibFuncs++;
-
- } /* if */
-
- Fp[0].Function_Name = savestr(Function_Name);
- Fp[0].Number_Args = Number_Args;
- Fp[0].Assignment_Type = Assignment_Type;
- Fp[0].Func_Ptr = Func_Ptr;
-
- } /* Func_Set */
-
-
- int Get_Nbr_Args()
- /************************************************************************/
- /* */
- /* return number of available arguments */
- /* */
- /************************************************************************/
- {
- register int n;
-
- if (Current_Act == NULL) return(0);
-
- if (Current_Act->Function == NULL) {
-
- for (n = 0; (1L<<n) & Current_Act->ArgFlags; n++) ;
- return(n);
-
- } /* if */
-
- return(Nbr_Kids(Current_Act->Function) - 1);
-
- } /* Get_Nbr_Args */
-
-
- double Get_Argument(n)
- register int n;
- /************************************************************************/
- /* */
- /* return nth argument for active function */
- /* */
- /************************************************************************/
- {
- register Activation_T *actp = Current_Act;
- Expression_T *Expr;
- double aval;
-
- if (actp == NULL || --n < 0) {
-
- fprintf(stderr, "Bad call to Get_Argument!\n");
- exit(1);
-
- } /* if */
- /* already computed? */
- if (1L<<n & actp->ArgFlags) return(actp->ArgTab[n]);
-
- if (actp->Function == NULL ||
- (Expr = Expr_Kid(actp->Function, n+1)) == NULL) {
-
- fprintf(stderr, "%s : too few arguments\n", actp->Function_Name);
- exit(1);
-
- } /* if */
-
- Current_Act = actp->Prev_Act; /* pop environment */
- aval = Expr_Value(Expr); /* compute argument */
- Current_Act = actp; /* push back environment */
-
- if (n < ALISTSIZ) { /* save value */
-
- actp->ArgTab[n] = aval;
- actp->ArgFlags |= 1L<<n;
-
- }
-
- return(aval);
-
- } /* Get_Argument */
-
-
- Variable_T *Get_Func_Arg(n)
- int n;
- /************************************************************************/
- /* */
- /* return function def for nth argument */
- /* */
- /************************************************************************/
- {
- register Activation_T *actp;
- register Expression_T *Expr;
-
- for (actp = Current_Act; actp != NULL; actp = actp->Prev_Act) {
-
- if (n <= 0) break;
-
- if (actp->Function == NULL) goto badarg;
-
- if ((Expr = Expr_Kid(actp->Function, n)) == NULL) {
-
- fprintf(stderr, "%s : too few arguments\n", actp->Function_Name);
- exit(1);
-
- } /* if */
-
- if (Expr->Node_Type == ET_Variable) return(Expr->Value.Variable);
-
- if (Expr->Node_Type != ET_Argument) goto badarg;
-
- n = Expr->Value.Channel; /* try previous context */
-
- } /* for */
-
- fprintf(stderr, "Bad call to Get_Func_Arg!\n");
-
- exit(1);
-
- badarg:
- fprintf(stderr, "%s : argument not a function\n", actp->Function_Name);
- exit(1);
-
- } /* Get_Func_Arg */
-
-
- char *Get_Func_Arg_Name(n)
- int n;
- /************************************************************************/
- /* */
- /* return function name for nth argument */
- /* */
- /************************************************************************/
- {
- return(Get_Func_Arg(n)->Name);
-
- } /* Get_Func_Arg_Name */
-
-
- double EFunc_Function(Expr)
- register Expression_T *Expr;
- /************************************************************************/
- /* */
- /* evaluate a function */
- /* */
- /************************************************************************/
- {
- Activation_T act;
- double alist[ALISTSIZ];
- double rval;
- register Variable_T *dp;
- /* push environment */
- dp = Resolve(Expr->Value.Kid);
-
- act.Function_Name = dp->Name;
- act.Prev_Act = Current_Act;
- act.ArgTab = alist;
- act.ArgFlags = 0;
- act.Function = Expr;
-
- Current_Act = &act;
-
- if (dp->Expression == NULL ||
- dp->Expression->Value.Kid->Node_Type != ET_Function) {
-
- rval = Func_Exec(act.Function_Name, dp);
-
- } else {
-
- rval = Expr_Value(dp->Expression->Value.Kid->Sibling);
-
- }
-
- Current_Act = act.Prev_Act; /* pop environment */
-
- return(rval);
-
- } /* EFunc_Function */
-
-
- Function_T *LibFunc_Lookup(Function_Name)
- char *Function_Name;
- /************************************************************************/
- /* */
- /* look up a library function */
- /* */
- /************************************************************************/
- {
- int upper, lower;
- register int cm, i;
-
- lower = 0;
- upper = cm = Nbr_LibFuncs;
-
- while ((i = (lower + upper) >> 1) != cm) {
-
- cm = strcmp(Function_Name, LibFuncs[i].Function_Name);
-
- if (cm > 0) lower = i;
- else if (cm < 0) upper = i;
- else return(&LibFuncs[i]);
-
- cm = i;
-
- } /* while */
-
- return(NULL);
-
- } /* LibFunc_Lookup */
-
- static double Func_Exec(Function_Name, vp)
- char *Function_Name;
- register Variable_T *vp;
- /************************************************************************/
- /* */
- /* execute library function */
- /* */
- /************************************************************************/
- {
- Variable_T dumdef;
- double d;
- int lasterrno;
-
- if (vp == NULL) {
-
- vp = &dumdef;
- vp->Function = NULL;
-
- } /* if */
-
- if (
- (
- (vp->Function == NULL ||
- strcmp(Function_Name, vp->Function->Function_Name)) &&
- (vp->Function = LibFunc_Lookup(Function_Name)) == NULL
- ) || vp->Function->Func_Ptr == NULL
-
- ) {
-
- fprintf(stderr, "%s : undefined function\n", Function_Name);
- exit(1);
- }
-
- lasterrno = errno;
- errno = 0;
-
- d = (*vp->Function->Func_Ptr)();
-
- #ifdef IEEE
- if (!finite(d)) errno = EDOM;
- #endif
-
- if (errno) {
- fprintf(stderr, "%s : bad call\n", Function_Name);
- 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 (Get_Argument(1) > 0.0) return(Get_Argument(2));
- else return(Get_Argument(3));
-
- } /* l_if */
-
-
- static double l_select()
- /************************************************************************/
- /* */
- /* return argument #(A1+1) */
- /* */
- /************************************************************************/
- {
- register int n;
-
- n = Get_Argument(1) + .5;
-
- if (n == 0) return( (double) (Get_Nbr_Args()-1) );
-
- if (n < 1 || n > Get_Nbr_Args()-1) {
-
- errno = EDOM;
- return(0.0);
-
- } /* if */
-
- return(Get_Argument(n+1));
-
- } /* l_select */
-
-
- static double l_rand()
- /************************************************************************/
- /* */
- /* random function between 0 and 1 */
- /* */
- /************************************************************************/
- {
- extern double floor();
- double x;
-
- x = Get_Argument(1);
- x *= 1.0/(1.0 + x*x) + 2.71828182845904;
- x += .785398163397447 - floor(x);
- x = 1e5 / x;
-
- return(x - floor(x));
-
- } /* l_rand */
-
-
- static double l_floor()
- /************************************************************************/
- /* */
- /* return largest integer not greater than arg1 */
- /* */
- /************************************************************************/
- {
- extern double floor();
-
- return(floor(Get_Argument(1)));
-
- } /* l_floor */
-
-
- static double l_ceil()
- /************************************************************************/
- /* */
- /* return smallest integer not less than arg1 */
- /* */
- /************************************************************************/
- {
- extern double ceil();
-
- return(ceil(Get_Argument(1)));
-
- } /* l_ceil */
-
-
- static double l_sqrt()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double sqrt();
-
- return(sqrt(Get_Argument(1)));
-
- } /* l_sqrt */
-
- static double l_sin()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double sin();
-
- return(sin(Get_Argument(1)));
-
- } /* l_sin */
-
-
- static double l_cos()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double cos();
-
- return(cos(Get_Argument(1)));
-
- } /* l_cos */
-
-
- static double l_tan()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double tan();
-
- return(tan(Get_Argument(1)));
-
- } /* l_tan */
-
-
- static double l_asin()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double asin();
-
- return(asin(Get_Argument(1)));
-
- } /* l_asin */
-
-
- static double l_acos()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double acos();
-
- return(acos(Get_Argument(1)));
-
- } /* l_acos */
-
-
- static double l_atan()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double atan();
-
- return(atan(Get_Argument(1)));
-
- } /* l_atan */
-
-
- static double l_atan2()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double atan2();
-
- return(atan2(Get_Argument(1), Get_Argument(2)));
-
- } /* l_atan2 */
-
-
- static double l_exp()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double exp();
-
- return(exp(Get_Argument(1)));
-
- } /* l_exp */
-
-
- static double l_log()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double log();
-
- return(log(Get_Argument(1)));
-
- } /* l_log */
-
-
- static double l_log10()
- /************************************************************************/
- /* */
- /* */
- /************************************************************************/
- {
- extern double log10();
-
- return(log10(Get_Argument(1)));
-
- } /* l_log10 */
-
-
- double l_bezier()
- /************************************************************************/
- /* */
- /* The bezier function: */
- /* */
- /* b(P1, P2, P3, P4, t) = P1 * (1-t)^3 + */
- /* P2 * 3 * t * (1-t)^2 + */
- /* P3 * 3 * t^2 * (1-t) + */
- /* P4 * t^3 */
- /* */
- /* Characteristics: */
- /* */
- /* b(0) = P0 db/dt(0) = 3(P2-P1) */
- /* b(1) = P4 db/dt(1) = 3(P4-P3) */
- /* */
- /* ie. a bezier curve passes through P0 with a tangent in the direction */
- /* of P1. It passes through P4 with a tangent from the direction of P3. */
- /* */
- /************************************************************************/
- {
- double t;
- double Get_Argument();
-
- t = Get_Argument(5);
- return(Get_Argument(1) * (1.+t*(-3.+t*(3.-t))) +
- Get_Argument(2) * 3.*t*(1.+t*(-2.+t)) +
- Get_Argument(3) * 3.*t*t*(1.-t) +
- Get_Argument(4) * t*t*t );
-
- } /* l_bezier */
-
-
- double l_bspline()
- /************************************************************************/
- /* */
- /* The bspline function. */
- /* */
- /************************************************************************/
- {
- double t;
- double Get_Argument();
-
- t = Get_Argument(5);
- return(Get_Argument(1) * (1./6.+t*(-1./2.+t*(1./2.-1./6.*t))) +
- Get_Argument(2) * (2./3.+t*t*(-1.+1./2.*t)) +
- Get_Argument(3) * (1./6.+t*(1./2.+t*(1./2.-1./2.*t))) +
- Get_Argument(4) * (1./6.*t*t*t) );
-
- } /* l_bspline */
-