ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.25
Committed: Thu Nov 7 23:19:54 2019 UTC (4 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.24: +3 -1 lines
Log Message:
Added shortcut (should not affect behavior)

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.25 static const char RCSid[] = "$Id: calfunc.c,v 2.24 2019/07/24 21:20:28 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * calfunc.c - routines for calcomp using functions.
6     *
7 greg 2.8 * If VARIABLE is not set, only library functions
8     * can be accessed.
9     *
10     * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
11     */
12    
13 greg 2.9 #include "copyright.h"
14 greg 1.1
15     #include <stdio.h>
16 schorsch 2.11 #include <string.h>
17 greg 1.1 #include <errno.h>
18 greg 2.5 #include <math.h>
19    
20 schorsch 2.12 #include "rterror.h"
21 greg 1.1 #include "calcomp.h"
22    
23 greg 1.5 /* bits in argument flag (better be right!) */
24     #define AFLAGSIZ (8*sizeof(unsigned long))
25 greg 2.19 #define ALISTSIZ 8 /* maximum saved argument list */
26 greg 1.1
27     typedef struct activation {
28     char *name; /* function name */
29     struct activation *prev; /* previous activation */
30     double *ap; /* argument list */
31     unsigned long an; /* computed argument flags */
32     EPNODE *fun; /* argument function */
33     } ACTIVATION; /* an activation record */
34    
35     static ACTIVATION *curact = NULL;
36    
37 schorsch 2.12 static double libfunc(char *fname, VARDEF *vp);
38 greg 1.1
39 greg 2.8 #ifndef MAXLIB
40 greg 1.1 #define MAXLIB 64 /* maximum number of library functions */
41 greg 2.8 #endif
42 greg 1.1
43 greg 2.21 static double l_if(char *), l_select(char *);
44     static double l_min(char *), l_max(char *);
45     static double l_rand(char *);
46 greg 2.13 static double l_floor(char *), l_ceil(char *);
47     static double l_sqrt(char *);
48     static double l_sin(char *), l_cos(char *), l_tan(char *);
49     static double l_asin(char *), l_acos(char *), l_atan(char *), l_atan2(char *);
50     static double l_exp(char *), l_log(char *), l_log10(char *);
51 greg 1.1
52     /* functions must be listed alphabetically */
53     static LIBR library[MAXLIB] = {
54 greg 1.4 { "acos", 1, ':', l_acos },
55     { "asin", 1, ':', l_asin },
56     { "atan", 1, ':', l_atan },
57     { "atan2", 2, ':', l_atan2 },
58     { "ceil", 1, ':', l_ceil },
59     { "cos", 1, ':', l_cos },
60     { "exp", 1, ':', l_exp },
61     { "floor", 1, ':', l_floor },
62     { "if", 3, ':', l_if },
63     { "log", 1, ':', l_log },
64     { "log10", 1, ':', l_log10 },
65 greg 2.21 { "max", 1, ':', l_max },
66     { "min", 1, ':', l_min },
67 greg 1.4 { "rand", 1, ':', l_rand },
68     { "select", 1, ':', l_select },
69     { "sin", 1, ':', l_sin },
70     { "sqrt", 1, ':', l_sqrt },
71     { "tan", 1, ':', l_tan },
72 greg 1.1 };
73    
74 greg 2.22 static int libsize = 18;
75 greg 1.1
76     #define resolve(ep) ((ep)->type==VAR?(ep)->v.ln:argf((ep)->v.chan))
77    
78    
79     int
80 greg 2.21 fundefined( /* return # of req'd arguments for function */
81 greg 2.16 char *fname
82     )
83 greg 1.1 {
84 greg 2.16 LIBR *lp;
85     VARDEF *vp;
86 greg 1.1
87 greg 2.7 if ((vp = varlookup(fname)) != NULL && vp->def != NULL
88     && vp->def->v.kid->type == FUNC)
89 greg 1.1 return(nekids(vp->def->v.kid) - 1);
90 greg 2.7 lp = vp != NULL ? vp->lib : liblookup(fname);
91     if (lp == NULL)
92     return(0);
93     return(lp->nargs);
94 greg 1.1 }
95    
96    
97     double
98 greg 2.16 funvalue( /* return a function value to the user */
99     char *fname,
100     int n,
101     double *a
102     )
103 greg 1.1 {
104     ACTIVATION act;
105 greg 2.16 VARDEF *vp;
106 greg 1.1 double rval;
107     /* push environment */
108     act.name = fname;
109     act.prev = curact;
110     act.ap = a;
111 greg 2.19 if (n < AFLAGSIZ)
112     act.an = (1L<<n)-1;
113     else {
114 greg 1.5 act.an = ~0;
115 greg 2.19 if (n > AFLAGSIZ)
116     wputs("Excess arguments in funvalue()\n");
117     }
118 greg 1.1 act.fun = NULL;
119     curact = &act;
120    
121     if ((vp = varlookup(fname)) == NULL || vp->def == NULL
122     || vp->def->v.kid->type != FUNC)
123     rval = libfunc(fname, vp);
124     else
125     rval = evalue(vp->def->v.kid->sibling);
126    
127     curact = act.prev; /* pop environment */
128     return(rval);
129     }
130    
131    
132 greg 2.8 void
133 greg 2.16 funset( /* set a library function */
134     char *fname,
135     int nargs,
136     int assign,
137     double (*fptr)(char *)
138     )
139 greg 1.1 {
140 greg 2.6 int oldlibsize = libsize;
141 greg 2.8 char *cp;
142 greg 2.16 LIBR *lp;
143 greg 2.8 /* check for context */
144     for (cp = fname; *cp; cp++)
145     ;
146     if (cp == fname)
147     return;
148 greg 2.21 while (cp[-1] == CNTXMARK) {
149 greg 2.8 *--cp = '\0';
150 greg 2.21 if (cp == fname) return;
151     }
152 greg 2.2 if ((lp = liblookup(fname)) == NULL) { /* insert */
153 greg 2.25 if (fptr == NULL)
154     return; /* nothing! */
155 greg 1.1 if (libsize >= MAXLIB) {
156     eputs("Too many library functons!\n");
157     quit(1);
158     }
159     for (lp = &library[libsize]; lp > library; lp--)
160 greg 2.17 if (strcmp(lp[-1].fname, fname) > 0)
161     lp[0] = lp[-1];
162     else
163 greg 1.1 break;
164     libsize++;
165     }
166 greg 2.2 if (fptr == NULL) { /* delete */
167     while (lp < &library[libsize-1]) {
168 greg 2.17 lp[0] = lp[1];
169 greg 2.2 lp++;
170     }
171     libsize--;
172     } else { /* or assign */
173     lp[0].fname = fname; /* string must be static! */
174     lp[0].nargs = nargs;
175     lp[0].atyp = assign;
176     lp[0].f = fptr;
177     }
178 greg 2.6 if (libsize != oldlibsize)
179     libupdate(fname); /* relink library */
180 greg 1.1 }
181    
182    
183     int
184 greg 2.16 nargum(void) /* return number of available arguments */
185 greg 1.1 {
186 greg 2.16 int n;
187 greg 1.1
188     if (curact == NULL)
189     return(0);
190     if (curact->fun == NULL) {
191     for (n = 0; (1L<<n) & curact->an; n++)
192     ;
193     return(n);
194     }
195     return(nekids(curact->fun) - 1);
196     }
197    
198    
199     double
200 greg 2.16 argument(int n) /* return nth argument for active function */
201 greg 1.1 {
202 greg 2.16 ACTIVATION *actp = curact;
203     EPNODE *ep = NULL;
204 greg 1.1 double aval;
205    
206 greg 2.21 if (!n) /* asking for # arguments? */
207     return((double)nargum());
208    
209 greg 2.19 if (!actp | (--n < 0)) {
210 greg 1.1 eputs("Bad call to argument!\n");
211     quit(1);
212     }
213 greg 2.20 if ((n < AFLAGSIZ) & actp->an >> n) /* already computed? */
214 greg 1.1 return(actp->ap[n]);
215    
216 greg 2.19 if (!actp->fun || !(ep = ekid(actp->fun, n+1))) {
217 greg 1.1 eputs(actp->name);
218     eputs(": too few arguments\n");
219     quit(1);
220     }
221 greg 2.19 curact = actp->prev; /* previous context */
222 greg 1.1 aval = evalue(ep); /* compute argument */
223 greg 2.20 curact = actp; /* put back calling context */
224     if (n < ALISTSIZ) { /* save value if room */
225 greg 1.1 actp->ap[n] = aval;
226     actp->an |= 1L<<n;
227     }
228     return(aval);
229     }
230    
231    
232     VARDEF *
233 greg 2.16 argf(int n) /* return function def for nth argument */
234 greg 1.1 {
235 greg 2.16 ACTIVATION *actp;
236     EPNODE *ep;
237 greg 1.1
238     for (actp = curact; actp != NULL; actp = actp->prev) {
239    
240     if (n <= 0)
241     break;
242    
243     if (actp->fun == NULL)
244     goto badarg;
245    
246     if ((ep = ekid(actp->fun, n)) == NULL) {
247     eputs(actp->name);
248     eputs(": too few arguments\n");
249     quit(1);
250     }
251     if (ep->type == VAR)
252     return(ep->v.ln); /* found it */
253    
254     if (ep->type != ARG)
255     goto badarg;
256    
257     n = ep->v.chan; /* try previous context */
258     }
259     eputs("Bad call to argf!\n");
260     quit(1);
261    
262     badarg:
263     eputs(actp->name);
264     eputs(": argument not a function\n");
265     quit(1);
266 schorsch 2.11 return NULL; /* pro forma return */
267 greg 1.1 }
268    
269    
270     char *
271 greg 2.16 argfun(int n) /* return function name for nth argument */
272 greg 1.1 {
273     return(argf(n)->name);
274     }
275    
276    
277     double
278 greg 2.16 efunc(EPNODE *ep) /* evaluate a function */
279 greg 1.1 {
280     ACTIVATION act;
281     double alist[ALISTSIZ];
282     double rval;
283 greg 2.16 VARDEF *dp;
284 greg 1.1 /* push environment */
285     dp = resolve(ep->v.kid);
286     act.name = dp->name;
287     act.prev = curact;
288     act.ap = alist;
289     act.an = 0;
290     act.fun = ep;
291     curact = &act;
292    
293     if (dp->def == NULL || dp->def->v.kid->type != FUNC)
294     rval = libfunc(act.name, dp);
295     else
296     rval = evalue(dp->def->v.kid->sibling);
297    
298     curact = act.prev; /* pop environment */
299     return(rval);
300     }
301    
302    
303     LIBR *
304 greg 2.16 liblookup(char *fname) /* look up a library function */
305 greg 1.1 {
306     int upper, lower;
307 greg 2.16 int cm, i;
308 greg 1.1
309     lower = 0;
310     upper = cm = libsize;
311    
312     while ((i = (lower + upper) >> 1) != cm) {
313     cm = strcmp(fname, library[i].fname);
314     if (cm > 0)
315     lower = i;
316     else if (cm < 0)
317     upper = i;
318     else
319     return(&library[i]);
320     cm = i;
321     }
322     return(NULL);
323     }
324    
325    
326     /*
327     * The following routines are for internal use:
328     */
329    
330    
331     static double
332 greg 2.16 libfunc( /* execute library function */
333     char *fname,
334     VARDEF *vp
335     )
336 greg 1.1 {
337 greg 2.16 LIBR *lp;
338 greg 1.1 double d;
339     int lasterrno;
340    
341 greg 2.3 if (vp != NULL)
342     lp = vp->lib;
343     else
344     lp = liblookup(fname);
345     if (lp == NULL) {
346 greg 1.1 eputs(fname);
347     eputs(": undefined function\n");
348     quit(1);
349     }
350     lasterrno = errno;
351     errno = 0;
352 greg 2.3 d = (*lp->f)(lp->fname);
353 greg 2.15 #ifdef isnan
354 greg 2.18 if (errno == 0) {
355 greg 1.9 if (isnan(d))
356     errno = EDOM;
357     else if (isinf(d))
358     errno = ERANGE;
359 greg 2.18 }
360 greg 1.1 #endif
361 greg 2.10 if (errno == EDOM || errno == ERANGE) {
362 greg 1.1 wputs(fname);
363 greg 1.8 if (errno == EDOM)
364     wputs(": domain error\n");
365     else if (errno == ERANGE)
366     wputs(": range error\n");
367     else
368     wputs(": error in call\n");
369 greg 1.1 return(0.0);
370     }
371     errno = lasterrno;
372     return(d);
373     }
374    
375    
376     /*
377     * Library functions:
378     */
379    
380    
381     static double
382 greg 2.13 l_if(char *nm) /* if(cond, then, else) conditional expression */
383 greg 1.1 /* cond evaluates true if greater than zero */
384     {
385     if (argument(1) > 0.0)
386     return(argument(2));
387     else
388     return(argument(3));
389     }
390    
391    
392     static double
393 greg 2.13 l_select(char *nm) /* return argument #(A1+1) */
394 greg 1.1 {
395 greg 2.23 int narg = nargum();
396     double a1 = argument(1);
397     int n = (int)(a1 + .5);
398 greg 1.1
399 greg 2.23 if (a1 < -.5 || n >= narg) {
400 greg 1.1 errno = EDOM;
401     return(0.0);
402     }
403 greg 2.23 if (!n) /* asking max index? */
404     return(narg-1);
405 greg 1.1 return(argument(n+1));
406     }
407    
408    
409     static double
410 greg 2.21 l_max(char *nm) /* general maximum function */
411     {
412     int n = nargum();
413     int i = 1;
414 greg 2.24 double vmax = argument(1);
415 greg 2.21
416     while (i++ < n) {
417     double v = argument(i);
418     if (vmax < v)
419     vmax = v;
420     }
421     return(vmax);
422     }
423    
424    
425     static double
426     l_min(char *nm) /* general minimum function */
427     {
428     int n = nargum();
429     int i = 1;
430 greg 2.24 double vmin = argument(1);
431 greg 2.21
432     while (i++ < n) {
433     double v = argument(i);
434     if (vmin > v)
435     vmin = v;
436     }
437     return(vmin);
438     }
439    
440    
441     static double
442 greg 2.13 l_rand(char *nm) /* random function between 0 and 1 */
443 greg 1.1 {
444     double x;
445    
446     x = argument(1);
447     x *= 1.0/(1.0 + x*x) + 2.71828182845904;
448     x += .785398163397447 - floor(x);
449     x = 1e5 / x;
450     return(x - floor(x));
451     }
452    
453    
454     static double
455 greg 2.13 l_floor(char *nm) /* return largest integer not greater than arg1 */
456 greg 1.1 {
457     return(floor(argument(1)));
458     }
459    
460    
461     static double
462 greg 2.13 l_ceil(char *nm) /* return smallest integer not less than arg1 */
463 greg 1.1 {
464     return(ceil(argument(1)));
465     }
466    
467    
468     static double
469 greg 2.13 l_sqrt(char *nm)
470 greg 1.1 {
471     return(sqrt(argument(1)));
472     }
473    
474    
475     static double
476 greg 2.13 l_sin(char *nm)
477 greg 1.1 {
478     return(sin(argument(1)));
479     }
480    
481    
482     static double
483 greg 2.13 l_cos(char *nm)
484 greg 1.1 {
485     return(cos(argument(1)));
486     }
487    
488    
489     static double
490 greg 2.13 l_tan(char *nm)
491 greg 1.1 {
492     return(tan(argument(1)));
493     }
494    
495    
496     static double
497 greg 2.13 l_asin(char *nm)
498 greg 1.1 {
499     return(asin(argument(1)));
500     }
501    
502    
503     static double
504 greg 2.13 l_acos(char *nm)
505 greg 1.1 {
506     return(acos(argument(1)));
507     }
508    
509    
510     static double
511 greg 2.13 l_atan(char *nm)
512 greg 1.1 {
513     return(atan(argument(1)));
514     }
515    
516    
517     static double
518 greg 2.13 l_atan2(char *nm)
519 greg 1.1 {
520     return(atan2(argument(1), argument(2)));
521     }
522    
523    
524     static double
525 greg 2.13 l_exp(char *nm)
526 greg 1.1 {
527     return(exp(argument(1)));
528     }
529    
530    
531     static double
532 greg 2.13 l_log(char *nm)
533 greg 1.1 {
534     return(log(argument(1)));
535     }
536    
537    
538     static double
539 greg 2.13 l_log10(char *nm)
540 greg 1.1 {
541     return(log10(argument(1)));
542     }