ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calfunc.c
Revision: 2.11
Committed: Sat Jun 7 12:50:20 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.10: +4 -4 lines
Log Message:
Various small changes to reduce compile warnings/errors on Windows.

File Contents

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