ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.20
Committed: Mon Mar 4 20:34:13 2019 UTC (5 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.19: +4 -4 lines
Log Message:
Removed parentheses for clarity(?)

File Contents

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