ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.1
Committed: Thu Feb 2 10:34:27 1989 UTC (35 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

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