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, 5 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calfunc.c,v 2.24 2019/07/24 21:20:28 greg Exp $";
3 #endif
4 /*
5 * calfunc.c - routines for calcomp using functions.
6 *
7 * 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 #include "copyright.h"
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <math.h>
19
20 #include "rterror.h"
21 #include "calcomp.h"
22
23 /* bits in argument flag (better be right!) */
24 #define AFLAGSIZ (8*sizeof(unsigned long))
25 #define ALISTSIZ 8 /* maximum saved argument list */
26
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 static double libfunc(char *fname, VARDEF *vp);
38
39 #ifndef MAXLIB
40 #define MAXLIB 64 /* maximum number of library functions */
41 #endif
42
43 static double l_if(char *), l_select(char *);
44 static double l_min(char *), l_max(char *);
45 static double l_rand(char *);
46 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
52 /* functions must be listed alphabetically */
53 static LIBR library[MAXLIB] = {
54 { "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 { "max", 1, ':', l_max },
66 { "min", 1, ':', l_min },
67 { "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 };
73
74 static int libsize = 18;
75
76 #define resolve(ep) ((ep)->type==VAR?(ep)->v.ln:argf((ep)->v.chan))
77
78
79 int
80 fundefined( /* return # of req'd arguments for function */
81 char *fname
82 )
83 {
84 LIBR *lp;
85 VARDEF *vp;
86
87 if ((vp = varlookup(fname)) != NULL && vp->def != NULL
88 && vp->def->v.kid->type == FUNC)
89 return(nekids(vp->def->v.kid) - 1);
90 lp = vp != NULL ? vp->lib : liblookup(fname);
91 if (lp == NULL)
92 return(0);
93 return(lp->nargs);
94 }
95
96
97 double
98 funvalue( /* return a function value to the user */
99 char *fname,
100 int n,
101 double *a
102 )
103 {
104 ACTIVATION act;
105 VARDEF *vp;
106 double rval;
107 /* push environment */
108 act.name = fname;
109 act.prev = curact;
110 act.ap = a;
111 if (n < AFLAGSIZ)
112 act.an = (1L<<n)-1;
113 else {
114 act.an = ~0;
115 if (n > AFLAGSIZ)
116 wputs("Excess arguments in funvalue()\n");
117 }
118 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 void
133 funset( /* set a library function */
134 char *fname,
135 int nargs,
136 int assign,
137 double (*fptr)(char *)
138 )
139 {
140 int oldlibsize = libsize;
141 char *cp;
142 LIBR *lp;
143 /* check for context */
144 for (cp = fname; *cp; cp++)
145 ;
146 if (cp == fname)
147 return;
148 while (cp[-1] == CNTXMARK) {
149 *--cp = '\0';
150 if (cp == fname) return;
151 }
152 if ((lp = liblookup(fname)) == NULL) { /* insert */
153 if (fptr == NULL)
154 return; /* nothing! */
155 if (libsize >= MAXLIB) {
156 eputs("Too many library functons!\n");
157 quit(1);
158 }
159 for (lp = &library[libsize]; lp > library; lp--)
160 if (strcmp(lp[-1].fname, fname) > 0)
161 lp[0] = lp[-1];
162 else
163 break;
164 libsize++;
165 }
166 if (fptr == NULL) { /* delete */
167 while (lp < &library[libsize-1]) {
168 lp[0] = lp[1];
169 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 if (libsize != oldlibsize)
179 libupdate(fname); /* relink library */
180 }
181
182
183 int
184 nargum(void) /* return number of available arguments */
185 {
186 int n;
187
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 argument(int n) /* return nth argument for active function */
201 {
202 ACTIVATION *actp = curact;
203 EPNODE *ep = NULL;
204 double aval;
205
206 if (!n) /* asking for # arguments? */
207 return((double)nargum());
208
209 if (!actp | (--n < 0)) {
210 eputs("Bad call to argument!\n");
211 quit(1);
212 }
213 if ((n < AFLAGSIZ) & actp->an >> n) /* already computed? */
214 return(actp->ap[n]);
215
216 if (!actp->fun || !(ep = ekid(actp->fun, n+1))) {
217 eputs(actp->name);
218 eputs(": too few arguments\n");
219 quit(1);
220 }
221 curact = actp->prev; /* previous context */
222 aval = evalue(ep); /* compute argument */
223 curact = actp; /* put back calling context */
224 if (n < ALISTSIZ) { /* save value if room */
225 actp->ap[n] = aval;
226 actp->an |= 1L<<n;
227 }
228 return(aval);
229 }
230
231
232 VARDEF *
233 argf(int n) /* return function def for nth argument */
234 {
235 ACTIVATION *actp;
236 EPNODE *ep;
237
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 return NULL; /* pro forma return */
267 }
268
269
270 char *
271 argfun(int n) /* return function name for nth argument */
272 {
273 return(argf(n)->name);
274 }
275
276
277 double
278 efunc(EPNODE *ep) /* evaluate a function */
279 {
280 ACTIVATION act;
281 double alist[ALISTSIZ];
282 double rval;
283 VARDEF *dp;
284 /* 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 liblookup(char *fname) /* look up a library function */
305 {
306 int upper, lower;
307 int cm, i;
308
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 libfunc( /* execute library function */
333 char *fname,
334 VARDEF *vp
335 )
336 {
337 LIBR *lp;
338 double d;
339 int lasterrno;
340
341 if (vp != NULL)
342 lp = vp->lib;
343 else
344 lp = liblookup(fname);
345 if (lp == NULL) {
346 eputs(fname);
347 eputs(": undefined function\n");
348 quit(1);
349 }
350 lasterrno = errno;
351 errno = 0;
352 d = (*lp->f)(lp->fname);
353 #ifdef isnan
354 if (errno == 0) {
355 if (isnan(d))
356 errno = EDOM;
357 else if (isinf(d))
358 errno = ERANGE;
359 }
360 #endif
361 if (errno == EDOM || errno == ERANGE) {
362 wputs(fname);
363 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 return(0.0);
370 }
371 errno = lasterrno;
372 return(d);
373 }
374
375
376 /*
377 * Library functions:
378 */
379
380
381 static double
382 l_if(char *nm) /* if(cond, then, else) conditional expression */
383 /* 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 l_select(char *nm) /* return argument #(A1+1) */
394 {
395 int narg = nargum();
396 double a1 = argument(1);
397 int n = (int)(a1 + .5);
398
399 if (a1 < -.5 || n >= narg) {
400 errno = EDOM;
401 return(0.0);
402 }
403 if (!n) /* asking max index? */
404 return(narg-1);
405 return(argument(n+1));
406 }
407
408
409 static double
410 l_max(char *nm) /* general maximum function */
411 {
412 int n = nargum();
413 int i = 1;
414 double vmax = argument(1);
415
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 double vmin = argument(1);
431
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 l_rand(char *nm) /* random function between 0 and 1 */
443 {
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 l_floor(char *nm) /* return largest integer not greater than arg1 */
456 {
457 return(floor(argument(1)));
458 }
459
460
461 static double
462 l_ceil(char *nm) /* return smallest integer not less than arg1 */
463 {
464 return(ceil(argument(1)));
465 }
466
467
468 static double
469 l_sqrt(char *nm)
470 {
471 return(sqrt(argument(1)));
472 }
473
474
475 static double
476 l_sin(char *nm)
477 {
478 return(sin(argument(1)));
479 }
480
481
482 static double
483 l_cos(char *nm)
484 {
485 return(cos(argument(1)));
486 }
487
488
489 static double
490 l_tan(char *nm)
491 {
492 return(tan(argument(1)));
493 }
494
495
496 static double
497 l_asin(char *nm)
498 {
499 return(asin(argument(1)));
500 }
501
502
503 static double
504 l_acos(char *nm)
505 {
506 return(acos(argument(1)));
507 }
508
509
510 static double
511 l_atan(char *nm)
512 {
513 return(atan(argument(1)));
514 }
515
516
517 static double
518 l_atan2(char *nm)
519 {
520 return(atan2(argument(1), argument(2)));
521 }
522
523
524 static double
525 l_exp(char *nm)
526 {
527 return(exp(argument(1)));
528 }
529
530
531 static double
532 l_log(char *nm)
533 {
534 return(log(argument(1)));
535 }
536
537
538 static double
539 l_log10(char *nm)
540 {
541 return(log10(argument(1)));
542 }