ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.4
Committed: Thu May 21 10:29:32 1992 UTC (31 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.3: +25 -2 lines
Log Message:
fixes for ev program

File Contents

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