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

# User Rev Content
1 greg 2.6 /* Copyright (c) 1992 Regents of the University of California */
2 greg 1.1
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 greg 2.5 #include <math.h>
24    
25 greg 1.1 #include "calcomp.h"
26    
27 greg 1.5 /* bits in argument flag (better be right!) */
28     #define AFLAGSIZ (8*sizeof(unsigned long))
29 greg 1.1 #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 greg 1.2 static double libfunc();
42 greg 1.1
43     #define MAXLIB 64 /* maximum number of library functions */
44    
45 greg 1.2 static double l_if(), l_select(), l_rand();
46     static double l_floor(), l_ceil();
47 greg 1.1 #ifdef BIGLIB
48 greg 1.2 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 greg 1.1 #endif
53    
54     #ifdef BIGLIB
55     /* functions must be listed alphabetically */
56     static LIBR library[MAXLIB] = {
57 greg 1.4 { "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 greg 1.1 };
74    
75     static int libsize = 16;
76    
77     #else
78     /* functions must be listed alphabetically */
79     static LIBR library[MAXLIB] = {
80 greg 1.4 { "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 greg 1.1 };
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 greg 1.5 if (n >= AFLAGSIZ)
135     act.an = ~0;
136     else
137     act.an = (1L<<n)-1;
138 greg 1.1 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 greg 1.4 funset(fname, nargs, assign, fptr) /* set a library function */
153 greg 1.1 char *fname;
154     int nargs;
155 greg 1.4 int assign;
156 greg 1.1 double (*fptr)();
157     {
158 greg 2.6 int oldlibsize = libsize;
159 greg 1.1 register LIBR *lp;
160    
161 greg 2.2 if ((lp = liblookup(fname)) == NULL) { /* insert */
162 greg 1.1 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 greg 1.4 lp[0].atyp = lp[-1].atyp;
171 greg 1.1 lp[0].f = lp[-1].f;
172     } else
173     break;
174     libsize++;
175     }
176 greg 2.2 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 greg 2.6 if (libsize != oldlibsize)
192     libupdate(fname); /* relink library */
193 greg 1.1 }
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 greg 1.7 register EPNODE *ep;
218 greg 1.1 double aval;
219    
220     if (actp == NULL || --n < 0) {
221     eputs("Bad call to argument!\n");
222     quit(1);
223     }
224     /* already computed? */
225 greg 1.5 if (n < AFLAGSIZ && 1L<<n & actp->an)
226 greg 1.1 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 greg 2.4 static VARDEF *varlist = NULL; /* our list of dummy variables */
345    
346    
347 greg 1.1 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 greg 2.4 vp->lib = liblookup(vname);
358     vp->next = varlist;
359     varlist = vp;
360 greg 1.1 return(vp);
361     }
362    
363    
364     varfree(vp) /* free dummy variable */
365     register VARDEF *vp;
366     {
367 greg 2.4 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 greg 1.1 freestr(vp->name);
377     efree((char *)vp);
378 greg 2.4 }
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 greg 1.1 }
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 greg 2.3 VARDEF *vp;
402 greg 1.1 {
403 greg 2.3 register LIBR *lp;
404 greg 1.1 double d;
405     int lasterrno;
406    
407 greg 2.3 if (vp != NULL)
408     lp = vp->lib;
409     else
410     lp = liblookup(fname);
411     if (lp == NULL) {
412 greg 1.1 eputs(fname);
413     eputs(": undefined function\n");
414     quit(1);
415     }
416     lasterrno = errno;
417     errno = 0;
418 greg 2.3 d = (*lp->f)(lp->fname);
419 greg 1.1 #ifdef IEEE
420 greg 1.9 if (errno == 0)
421     if (isnan(d))
422     errno = EDOM;
423     else if (isinf(d))
424     errno = ERANGE;
425 greg 1.1 #endif
426     if (errno) {
427     wputs(fname);
428 greg 1.8 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 greg 1.1 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