ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.11
Committed: Sat Jun 7 12:50:20 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.10: +4 -4 lines
Log Message:
Various small changes to reduce compile warnings/errors on Windows.

File Contents

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