ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.5
Committed: Tue Jun 26 09:15:11 1990 UTC (33 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.4: +4 -3 lines
Log Message:
nit-picking for Stardent compiler

File Contents

# User Rev Content
1 greg 1.1 /* Copyright (c) 1986 Regents of the University of California */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * Compute data values using expression parser
9     *
10     * 7/1/85 Greg Ward
11     *
12     * 11/11/85 Made channel input conditional with (INCHAN) compiles.
13     *
14     * 4/2/86 Added conditional compiles for function definitions (FUNCTION).
15     *
16     * 1/29/87 Made variables conditional (VARIABLE)
17     *
18     * 5/19/88 Added constant subexpression elimination (RCONST)
19     */
20    
21     #include <stdio.h>
22    
23     #include <ctype.h>
24    
25     #include <errno.h>
26    
27     #include "calcomp.h"
28    
29     #define MAXLINE 256 /* maximum line length */
30     #define MAXWORD 64 /* maximum word length */
31    
32     #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
33    
34     #define isid(c) (isalnum(c) || (c) == '_' || (c) == '.')
35    
36     #define isdecimal(c) (isdigit(c) || (c) == '.')
37    
38     extern double atof(), pow();
39     extern char *fgets(), *savestr();
40     extern char *emalloc(), *ecalloc();
41     extern EPNODE *curfunc;
42 greg 1.5 extern double efunc(), evariable();
43     static double euminus(), echannel(), eargument(), enumber();
44     static double eadd(), esubtr(), emult(), edivi(), epow();
45     static double ebotch();
46 greg 1.1 extern int errno;
47    
48     int nextc; /* lookahead character */
49    
50     double (*eoper[])() = { /* expression operations */
51     ebotch,
52     #ifdef VARIABLE
53     evariable,
54     #else
55     ebotch,
56     #endif
57     enumber,
58     euminus,
59     #ifdef INCHAN
60     echannel,
61     #else
62     ebotch,
63     #endif
64     #ifdef FUNCTION
65     efunc,
66     eargument,
67     #else
68     ebotch,
69     ebotch,
70     #endif
71     ebotch,
72     ebotch,
73     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
74     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
75     emult,
76     eadd,
77     0,
78     esubtr,
79     0,
80     edivi,
81     0,0,0,0,0,0,0,0,0,0,0,0,0,
82     ebotch,
83     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
84     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
85     epow,
86     };
87    
88     static char *infile; /* input file name */
89     static FILE *infp; /* input file pointer */
90     static char *linbuf; /* line buffer */
91     static int linepos; /* position in buffer */
92    
93    
94     EPNODE *
95     eparse(expr) /* parse an expression string */
96     char *expr;
97     {
98     EPNODE *ep;
99    
100     initstr(NULL, expr);
101     #if defined(VARIABLE) && defined(FUNCTION)
102     curfunc = NULL;
103     #endif
104     ep = getE1();
105     if (nextc != EOF)
106     syntax("unexpected character");
107     return(ep);
108     }
109    
110    
111     double
112     eval(expr) /* evaluate an expression string */
113     char *expr;
114     {
115     register EPNODE *ep;
116     double rval;
117    
118     ep = eparse(expr);
119     rval = evalue(ep);
120     epfree(ep);
121     return(rval);
122     }
123    
124    
125     epfree(epar) /* free a parse tree */
126     register EPNODE *epar;
127     {
128     register EPNODE *ep;
129    
130     switch (epar->type) {
131    
132 greg 1.2 #if defined(VARIABLE) || defined(FUNCTION)
133 greg 1.1 case VAR:
134     varfree(epar->v.ln);
135     break;
136 greg 1.2 #endif
137 greg 1.1
138     case SYM:
139     freestr(epar->v.name);
140     break;
141    
142     case NUM:
143     case CHAN:
144     case ARG:
145     case TICK:
146     break;
147    
148     default:
149     for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
150     epfree(ep);
151     break;
152    
153     }
154    
155     efree((char *)epar);
156     }
157    
158     /* the following used to be a switch */
159     #ifdef FUNCTION
160     static double
161     eargument(ep)
162     EPNODE *ep;
163     {
164     return(argument(ep->v.chan));
165     }
166     #endif
167    
168     static double
169     enumber(ep)
170     EPNODE *ep;
171     {
172     return(ep->v.num);
173     }
174    
175     static double
176     euminus(ep)
177     EPNODE *ep;
178     {
179     register EPNODE *ep1 = ep->v.kid;
180    
181     return(-evalue(ep1));
182     }
183    
184     #ifdef INCHAN
185     static double
186     echannel(ep)
187     EPNODE *ep;
188     {
189     return(chanvalue(ep->v.chan));
190     }
191     #endif
192    
193     static double
194     eadd(ep)
195     EPNODE *ep;
196     {
197     register EPNODE *ep1 = ep->v.kid;
198    
199     return(evalue(ep1) + evalue(ep1->sibling));
200     }
201    
202     static double
203     esubtr(ep)
204     EPNODE *ep;
205     {
206     register EPNODE *ep1 = ep->v.kid;
207    
208     return(evalue(ep1) - evalue(ep1->sibling));
209     }
210    
211     static double
212     emult(ep)
213     EPNODE *ep;
214     {
215     register EPNODE *ep1 = ep->v.kid;
216    
217     return(evalue(ep1) * evalue(ep1->sibling));
218     }
219    
220     static double
221     edivi(ep)
222     EPNODE *ep;
223     {
224     register EPNODE *ep1 = ep->v.kid;
225     double d;
226    
227     d = evalue(ep1->sibling);
228     if (d == 0.0) {
229     wputs("Division by zero\n");
230     errno = ERANGE;
231     return(0.0);
232     }
233     return(evalue(ep1) / d);
234     }
235    
236     static double
237     epow(ep)
238     EPNODE *ep;
239     {
240     register EPNODE *ep1 = ep->v.kid;
241     double d;
242     int lasterrno;
243    
244     lasterrno = errno;
245     errno = 0;
246     d = pow(evalue(ep1), evalue(ep1->sibling));
247     #ifdef IEEE
248     if (!finite(d))
249     errno = EDOM;
250     #endif
251     if (errno) {
252     wputs("Illegal power\n");
253     return(0.0);
254     }
255     errno = lasterrno;
256     return(d);
257     }
258    
259     static double
260     ebotch(ep)
261     EPNODE *ep;
262     {
263     eputs("Bad expression!\n");
264     quit(1);
265     }
266    
267    
268     EPNODE *
269     ekid(ep, n) /* return pointer to a node's nth kid */
270     register EPNODE *ep;
271     register int n;
272     {
273    
274     for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
275     if (--n < 0)
276     break;
277    
278     return(ep);
279     }
280    
281    
282     int
283     nekids(ep) /* return # of kids for node ep */
284     register EPNODE *ep;
285     {
286     register int n = 0;
287    
288     for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
289     n++;
290    
291     return(n);
292     }
293    
294    
295     initfile(file, fp) /* prepare input file */
296     char *file;
297     FILE *fp;
298     {
299     static char inpbuf[MAXLINE];
300    
301     infile = file;
302     infp = fp;
303     linbuf = inpbuf;
304     linepos = 0;
305     inpbuf[0] = '\0';
306     scan();
307     }
308    
309    
310     initstr(file, s) /* prepare input string */
311     char *file;
312     char *s;
313     {
314     infile = file;
315     infp = NULL;
316     linbuf = s;
317     linepos = 0;
318     scan();
319     }
320    
321    
322     scan() /* scan next character */
323     {
324     do {
325     if (linbuf[linepos] == '\0')
326     if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
327     nextc = EOF;
328     else {
329     nextc = linbuf[0];
330     linepos = 1;
331     }
332     else
333     nextc = linbuf[linepos++];
334     if (nextc == '{') {
335     scan();
336     while (nextc != '}')
337     if (nextc == EOF)
338     syntax("'}' expected");
339     else
340     scan();
341     scan();
342     }
343     } while (isspace(nextc));
344     }
345    
346    
347     syntax(err) /* report syntax error and quit */
348     char *err;
349     {
350     register int i;
351    
352     eputs(linbuf);
353 greg 1.4 if (linbuf[strlen(linbuf)-1] != '\n')
354 greg 1.1 eputs("\n");
355     for (i = 0; i < linepos-1; i++)
356     eputs(linbuf[i] == '\t' ? "\t" : " ");
357     eputs("^ ");
358     if (infile != NULL) {
359     eputs(infile);
360     eputs(": ");
361     }
362     eputs(err);
363     eputs("\n");
364     quit(1);
365     }
366    
367    
368     addekid(ep, ekid) /* add a child to ep */
369     register EPNODE *ep;
370     EPNODE *ekid;
371     {
372     if (ep->v.kid == NULL)
373     ep->v.kid = ekid;
374     else {
375     for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
376     ;
377     ep->sibling = ekid;
378     }
379     ekid->sibling = NULL;
380     }
381    
382    
383     char *
384     getname() /* scan an identifier */
385     {
386     static char str[MAXWORD+1];
387     register int i;
388    
389     for (i = 0; i < MAXWORD && isid(nextc); i++, scan())
390     str[i] = nextc;
391     str[i] = '\0';
392    
393     return(str);
394     }
395    
396    
397     int
398     getinum() /* scan a positive integer */
399     {
400     register int n;
401    
402     n = 0;
403     while (isdigit(nextc)) {
404     n = n * 10 + nextc - '0';
405     scan();
406     }
407     return(n);
408     }
409    
410    
411     double
412     getnum() /* scan a positive float */
413     {
414     register int i;
415     char str[MAXWORD+1];
416    
417     i = 0;
418     while (isdigit(nextc) && i < MAXWORD) {
419     str[i++] = nextc;
420     scan();
421     }
422     if (nextc == '.' && i < MAXWORD) {
423     str[i++] = nextc;
424     scan();
425     while (isdigit(nextc) && i < MAXWORD) {
426     str[i++] = nextc;
427     scan();
428     }
429     }
430     if ((nextc == 'e' || nextc == 'E') && i < MAXWORD) {
431     str[i++] = nextc;
432     scan();
433     if ((nextc == '-' || nextc == '+') && i < MAXWORD) {
434     str[i++] = nextc;
435     scan();
436     }
437     while (isdigit(nextc) && i < MAXWORD) {
438     str[i++] = nextc;
439     scan();
440     }
441     }
442     str[i] = '\0';
443    
444     return(atof(str));
445     }
446    
447    
448     EPNODE *
449     getE1() /* E1 -> E1 ADDOP E2 */
450     /* E2 */
451     {
452     register EPNODE *ep1, *ep2;
453    
454     ep1 = getE2();
455     while (nextc == '+' || nextc == '-') {
456     ep2 = newnode();
457     ep2->type = nextc;
458     scan();
459     addekid(ep2, ep1);
460     addekid(ep2, getE2());
461     #ifdef RCONST
462     if (ep1->type == NUM && ep1->sibling->type == NUM)
463     ep2 = rconst(ep2);
464     #endif
465     ep1 = ep2;
466     }
467     return(ep1);
468     }
469    
470    
471     EPNODE *
472     getE2() /* E2 -> E2 MULOP E3 */
473     /* E3 */
474     {
475     register EPNODE *ep1, *ep2;
476    
477     ep1 = getE3();
478     while (nextc == '*' || nextc == '/') {
479     ep2 = newnode();
480     ep2->type = nextc;
481     scan();
482     addekid(ep2, ep1);
483     addekid(ep2, getE3());
484     #ifdef RCONST
485     if (ep1->type == NUM && ep1->sibling->type == NUM)
486     ep2 = rconst(ep2);
487     #endif
488     ep1 = ep2;
489     }
490     return(ep1);
491     }
492    
493    
494     EPNODE *
495     getE3() /* E3 -> E3 ^ E4 */
496     /* E4 */
497     {
498     register EPNODE *ep1, *ep2;
499    
500     ep1 = getE4();
501     while (nextc == '^') {
502     ep2 = newnode();
503     ep2->type = nextc;
504     scan();
505     addekid(ep2, ep1);
506     addekid(ep2, getE4());
507     #ifdef RCONST
508     if (ep1->type == NUM && ep1->sibling->type == NUM)
509     ep2 = rconst(ep2);
510     #endif
511     ep1 = ep2;
512     }
513     return(ep1);
514     }
515    
516    
517     EPNODE *
518     getE4() /* E4 -> ADDOP E5 */
519     /* E5 */
520     {
521 greg 1.3 register EPNODE *ep1, *ep2;
522 greg 1.1
523     if (nextc == '-') {
524     scan();
525 greg 1.3 ep2 = getE5();
526     if (ep2->type == NUM) {
527     ep2->v.num = -ep2->v.num;
528     return(ep2);
529     }
530 greg 1.1 ep1 = newnode();
531     ep1->type = UMINUS;
532 greg 1.3 addekid(ep1, ep2);
533 greg 1.1 return(ep1);
534     }
535     if (nextc == '+')
536     scan();
537     return(getE5());
538     }
539    
540    
541     EPNODE *
542     getE5() /* E5 -> (E1) */
543     /* VAR */
544     /* NUM */
545     /* $N */
546     /* FUNC(E1,..) */
547     /* ARG */
548     {
549     int i;
550     register EPNODE *ep1, *ep2;
551    
552     if (nextc == '(') {
553     scan();
554     ep1 = getE1();
555     if (nextc != ')')
556     syntax("')' expected");
557     scan();
558     return(ep1);
559     }
560    
561     #ifdef INCHAN
562     if (nextc == '$') {
563     scan();
564     ep1 = newnode();
565     ep1->type = CHAN;
566     ep1->v.chan = getinum();
567     return(ep1);
568     }
569     #endif
570    
571     #if defined(VARIABLE) || defined(FUNCTION)
572     if (isalpha(nextc)) {
573     ep1 = newnode();
574     ep1->type = VAR;
575     ep1->v.ln = varinsert(getname());
576    
577     #if defined(VARIABLE) && defined(FUNCTION)
578     if (curfunc != NULL)
579     for (i = 1, ep2 = curfunc->v.kid->sibling;
580     ep2 != NULL; i++, ep2 = ep2->sibling)
581     if (!strcmp(ep2->v.name, ep1->v.ln->name)) {
582     epfree(ep1);
583     ep1 = newnode();
584     ep1->type = ARG;
585     ep1->v.chan = i;
586     break;
587     }
588     #endif
589     #ifdef FUNCTION
590     if (nextc == '(') {
591     ep2 = newnode();
592     ep2->type = FUNC;
593     addekid(ep2, ep1);
594     ep1 = ep2;
595     do {
596     scan();
597     addekid(ep1, getE1());
598     } while (nextc == ',');
599     if (nextc != ')')
600     syntax("')' expected");
601     scan();
602     }
603     #ifndef VARIABLE
604     else
605     syntax("'(' expected");
606     #endif
607     #endif
608     return(ep1);
609     }
610     #endif
611    
612     if (isdecimal(nextc)) {
613     ep1 = newnode();
614     ep1->type = NUM;
615     ep1->v.num = getnum();
616     return(ep1);
617     }
618     syntax("unexpected character");
619     }
620    
621    
622     #ifdef RCONST
623     EPNODE *
624     rconst(epar) /* reduce a constant expression */
625     register EPNODE *epar;
626     {
627     register EPNODE *ep;
628    
629     ep = newnode();
630     ep->type = NUM;
631     errno = 0;
632     ep->v.num = evalue(epar);
633     if (errno)
634     syntax("bad constant expression");
635     epfree(epar);
636    
637     return(ep);
638     }
639     #endif