ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.13
Committed: Mon Aug 4 22:37:53 2003 UTC (20 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.12: +24 -24 lines
Log Message:
Added prototype for LIBR function pointer in calcomp.h

File Contents

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