ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.7
Committed: Sun Nov 22 17:29:46 1992 UTC (31 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +7 -8 lines
Log Message:
minor improvement in fundefined()

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