ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.6
Committed: Sun Nov 22 12:11:48 1992 UTC (31 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.5: +4 -2 lines
Log Message:
calls libupdate() only when necessary

File Contents

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