ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.34
Committed: Sun Jul 25 05:50:27 2010 UTC (13 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.33: +43 -16 lines
Log Message:
Added reduction of constant expressions (0*x), (x*0), (0/x), (1^x), (0^x), (x^0)

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calexpr.c,v 2.33 2009/06/14 18:21:58 greg Exp $";
3 #endif
4 /*
5 * Compute data values using expression parser
6 *
7 * 7/1/85 Greg Ward
8 *
9 * 11/11/85 Made channel input conditional with (INCHAN) compiles.
10 *
11 * 4/2/86 Added conditional compiles for function definitions (FUNCTION).
12 *
13 * 1/29/87 Made variables conditional (VARIABLE)
14 *
15 * 5/19/88 Added constant subexpression elimination (RCONST)
16 *
17 * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
18 */
19
20 #include "copyright.h"
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <math.h>
27 #include <stdlib.h>
28
29 #include "rtmisc.h"
30 #include "rtio.h"
31 #include "rterror.h"
32 #include "calcomp.h"
33
34 #define MAXLINE 256 /* maximum line length */
35
36 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
37
38 #define isdecimal(c) (isdigit(c) || (c) == '.')
39
40 static double euminus(EPNODE *), eargument(EPNODE *), enumber(EPNODE *);
41 static double echannel(EPNODE *);
42 static double eadd(EPNODE *), esubtr(EPNODE *),
43 emult(EPNODE *), edivi(EPNODE *),
44 epow(EPNODE *);
45 static double ebotch(EPNODE *);
46
47 unsigned int esupport = /* what to support */
48 E_VARIABLE | E_FUNCTION ;
49
50 int eofc = 0; /* optional end-of-file character */
51 int nextc; /* lookahead character */
52
53 double (*eoper[])(EPNODE *) = { /* expression operations */
54 ebotch,
55 evariable,
56 enumber,
57 euminus,
58 echannel,
59 efunc,
60 eargument,
61 ebotch,
62 ebotch,
63 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
64 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
65 emult,
66 eadd,
67 0,
68 esubtr,
69 0,
70 edivi,
71 0,0,0,0,0,0,0,0,0,0,
72 ebotch,
73 0,0,
74 ebotch,
75 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
76 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
77 epow,
78 };
79
80 static FILE *infp; /* input file pointer */
81 static char *linbuf; /* line buffer */
82 static char *infile; /* input file name */
83 static int lineno; /* input line number */
84 static int linepos; /* position in buffer */
85
86
87 EPNODE *
88 eparse( /* parse an expression string */
89 char *expr
90 )
91 {
92 EPNODE *ep;
93
94 initstr(expr, NULL, 0);
95 curfunc = NULL;
96 ep = getE1();
97 if (nextc != EOF)
98 syntax("unexpected character");
99 return(ep);
100 }
101
102
103 double
104 eval( /* evaluate an expression string */
105 char *expr
106 )
107 {
108 register EPNODE *ep;
109 double rval;
110
111 ep = eparse(expr);
112 rval = evalue(ep);
113 epfree(ep);
114 return(rval);
115 }
116
117
118 int
119 epcmp( /* compare two expressions for equivalence */
120 register EPNODE *ep1,
121 register EPNODE *ep2
122 )
123 {
124 double d;
125
126 if (ep1->type != ep2->type)
127 return(1);
128
129 switch (ep1->type) {
130
131 case VAR:
132 return(ep1->v.ln != ep2->v.ln);
133
134 case NUM:
135 if (ep2->v.num == 0)
136 return(ep1->v.num != 0);
137 d = ep1->v.num / ep2->v.num;
138 return((d > 1.000000000001) | (d < 0.999999999999));
139
140 case CHAN:
141 case ARG:
142 return(ep1->v.chan != ep2->v.chan);
143
144 case '=':
145 case ':':
146 return(epcmp(ep1->v.kid->sibling, ep2->v.kid->sibling));
147
148 case CLKT:
149 case SYM: /* should never get this one */
150 return(0);
151
152 default:
153 ep1 = ep1->v.kid;
154 ep2 = ep2->v.kid;
155 while (ep1 != NULL) {
156 if (ep2 == NULL)
157 return(1);
158 if (epcmp(ep1, ep2))
159 return(1);
160 ep1 = ep1->sibling;
161 ep2 = ep2->sibling;
162 }
163 return(ep2 != NULL);
164 }
165 }
166
167
168 void
169 epfree( /* free a parse tree */
170 register EPNODE *epar
171 )
172 {
173 register EPNODE *ep;
174
175 switch (epar->type) {
176
177 case VAR:
178 varfree(epar->v.ln);
179 break;
180
181 case SYM:
182 freestr(epar->v.name);
183 break;
184
185 case NUM:
186 case CHAN:
187 case ARG:
188 case CLKT:
189 break;
190
191 default:
192 while ((ep = epar->v.kid) != NULL) {
193 epar->v.kid = ep->sibling;
194 epfree(ep);
195 }
196 break;
197
198 }
199
200 efree((char *)epar);
201 }
202
203 /* the following used to be a switch */
204 static double
205 eargument(
206 EPNODE *ep
207 )
208 {
209 return(argument(ep->v.chan));
210 }
211
212 static double
213 enumber(
214 EPNODE *ep
215 )
216 {
217 return(ep->v.num);
218 }
219
220 static double
221 euminus(
222 EPNODE *ep
223 )
224 {
225 register EPNODE *ep1 = ep->v.kid;
226
227 return(-evalue(ep1));
228 }
229
230 static double
231 echannel(
232 EPNODE *ep
233 )
234 {
235 return(chanvalue(ep->v.chan));
236 }
237
238 static double
239 eadd(
240 EPNODE *ep
241 )
242 {
243 register EPNODE *ep1 = ep->v.kid;
244
245 return(evalue(ep1) + evalue(ep1->sibling));
246 }
247
248 static double
249 esubtr(
250 EPNODE *ep
251 )
252 {
253 register EPNODE *ep1 = ep->v.kid;
254
255 return(evalue(ep1) - evalue(ep1->sibling));
256 }
257
258 static double
259 emult(
260 EPNODE *ep
261 )
262 {
263 register EPNODE *ep1 = ep->v.kid;
264
265 return(evalue(ep1) * evalue(ep1->sibling));
266 }
267
268 static double
269 edivi(
270 EPNODE *ep
271 )
272 {
273 register EPNODE *ep1 = ep->v.kid;
274 double d;
275
276 d = evalue(ep1->sibling);
277 if (d == 0.0) {
278 wputs("Division by zero\n");
279 errno = ERANGE;
280 return(0.0);
281 }
282 return(evalue(ep1) / d);
283 }
284
285 static double
286 epow(
287 EPNODE *ep
288 )
289 {
290 register EPNODE *ep1 = ep->v.kid;
291 double d;
292 int lasterrno;
293
294 lasterrno = errno;
295 errno = 0;
296 d = pow(evalue(ep1), evalue(ep1->sibling));
297 #ifdef isnan
298 if (errno == 0)
299 if (isnan(d))
300 errno = EDOM;
301 else if (isinf(d))
302 errno = ERANGE;
303 #endif
304 if (errno == EDOM || errno == ERANGE) {
305 wputs("Illegal power\n");
306 return(0.0);
307 }
308 errno = lasterrno;
309 return(d);
310 }
311
312 static double
313 ebotch(
314 EPNODE *ep
315 )
316 {
317 eputs("Bad expression!\n");
318 quit(1);
319 return 0.0; /* pro forma return */
320 }
321
322
323 EPNODE *
324 ekid( /* return pointer to a node's nth kid */
325 register EPNODE *ep,
326 register int n
327 )
328 {
329
330 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
331 if (--n < 0)
332 break;
333
334 return(ep);
335 }
336
337
338 int
339 nekids( /* return # of kids for node ep */
340 register EPNODE *ep
341 )
342 {
343 register int n = 0;
344
345 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
346 n++;
347
348 return(n);
349 }
350
351
352 void
353 initfile( /* prepare input file */
354 FILE *fp,
355 char *fn,
356 int ln
357 )
358 {
359 static char inpbuf[MAXLINE];
360
361 infp = fp;
362 linbuf = inpbuf;
363 infile = fn;
364 lineno = ln;
365 linepos = 0;
366 inpbuf[0] = '\0';
367 scan();
368 }
369
370
371 void
372 initstr( /* prepare input string */
373 char *s,
374 char *fn,
375 int ln
376 )
377 {
378 infp = NULL;
379 infile = fn;
380 lineno = ln;
381 linbuf = s;
382 linepos = 0;
383 scan();
384 }
385
386
387 void
388 getscanpos( /* return current scan position */
389 char **fnp,
390 int *lnp,
391 char **spp,
392 FILE **fpp
393 )
394 {
395 if (fnp != NULL) *fnp = infile;
396 if (lnp != NULL) *lnp = lineno;
397 if (spp != NULL) *spp = linbuf+linepos;
398 if (fpp != NULL) *fpp = infp;
399 }
400
401
402 int
403 scan(void) /* scan next character, return literal next */
404 {
405 register int lnext = 0;
406
407 do {
408 if (linbuf[linepos] == '\0')
409 if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
410 nextc = EOF;
411 else {
412 nextc = linbuf[0];
413 lineno++;
414 linepos = 1;
415 }
416 else
417 nextc = linbuf[linepos++];
418 if (!lnext)
419 lnext = nextc;
420 if (nextc == eofc) {
421 nextc = EOF;
422 break;
423 }
424 if (nextc == '{') {
425 scan();
426 while (nextc != '}')
427 if (nextc == EOF)
428 syntax("'}' expected");
429 else
430 scan();
431 scan();
432 }
433 } while (isspace(nextc));
434 return(lnext);
435 }
436
437
438 char *
439 long2ascii( /* convert long to ascii */
440 long l
441 )
442 {
443 static char buf[16];
444 register char *cp;
445 int neg = 0;
446
447 if (l == 0)
448 return("0");
449 if (l < 0) {
450 l = -l;
451 neg++;
452 }
453 cp = buf + sizeof(buf);
454 *--cp = '\0';
455 while (l) {
456 *--cp = l % 10 + '0';
457 l /= 10;
458 }
459 if (neg)
460 *--cp = '-';
461 return(cp);
462 }
463
464
465 void
466 syntax( /* report syntax error and quit */
467 char *err
468 )
469 {
470 register int i;
471
472 if (infile != NULL || lineno != 0) {
473 if (infile != NULL) eputs(infile);
474 if (lineno != 0) {
475 eputs(infile != NULL ? ", line " : "line ");
476 eputs(long2ascii((long)lineno));
477 }
478 eputs(":\n");
479 }
480 eputs(linbuf);
481 if (linbuf[strlen(linbuf)-1] != '\n')
482 eputs("\n");
483 for (i = 0; i < linepos-1; i++)
484 eputs(linbuf[i] == '\t' ? "\t" : " ");
485 eputs("^ ");
486 eputs(err);
487 eputs("\n");
488 quit(1);
489 }
490
491
492 void
493 addekid( /* add a child to ep */
494 register EPNODE *ep,
495 EPNODE *ekid
496 )
497 {
498 if (ep->v.kid == NULL)
499 ep->v.kid = ekid;
500 else {
501 for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
502 ;
503 ep->sibling = ekid;
504 }
505 ekid->sibling = NULL;
506 }
507
508
509 char *
510 getname(void) /* scan an identifier */
511 {
512 static char str[RMAXWORD+1];
513 register int i, lnext;
514
515 lnext = nextc;
516 for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = scan())
517 str[i] = lnext;
518 str[i] = '\0';
519 while (isid(lnext)) /* skip rest of name */
520 lnext = scan();
521
522 return(str);
523 }
524
525
526 int
527 getinum(void) /* scan a positive integer */
528 {
529 register int n, lnext;
530
531 n = 0;
532 lnext = nextc;
533 while (isdigit(lnext)) {
534 n = n * 10 + lnext - '0';
535 lnext = scan();
536 }
537 return(n);
538 }
539
540
541 double
542 getnum(void) /* scan a positive float */
543 {
544 register int i, lnext;
545 char str[RMAXWORD+1];
546
547 i = 0;
548 lnext = nextc;
549 while (isdigit(lnext) && i < RMAXWORD) {
550 str[i++] = lnext;
551 lnext = scan();
552 }
553 if (lnext == '.' && i < RMAXWORD) {
554 str[i++] = lnext;
555 lnext = scan();
556 if (i == 1 && !isdigit(lnext))
557 syntax("badly formed number");
558 while (isdigit(lnext) && i < RMAXWORD) {
559 str[i++] = lnext;
560 lnext = scan();
561 }
562 }
563 if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) {
564 str[i++] = lnext;
565 lnext = scan();
566 if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) {
567 str[i++] = lnext;
568 lnext = scan();
569 }
570 if (!isdigit(lnext))
571 syntax("missing exponent");
572 while (isdigit(lnext) && i < RMAXWORD) {
573 str[i++] = lnext;
574 lnext = scan();
575 }
576 }
577 str[i] = '\0';
578
579 return(atof(str));
580 }
581
582
583 EPNODE *
584 getE1(void) /* E1 -> E1 ADDOP E2 */
585 /* E2 */
586 {
587 register EPNODE *ep1, *ep2;
588
589 ep1 = getE2();
590 while (nextc == '+' || nextc == '-') {
591 ep2 = newnode();
592 ep2->type = nextc;
593 scan();
594 addekid(ep2, ep1);
595 addekid(ep2, getE2());
596 if (esupport&E_RCONST &&
597 ep1->type == NUM && ep1->sibling->type == NUM)
598 ep2 = rconst(ep2);
599 ep1 = ep2;
600 }
601 return(ep1);
602 }
603
604
605 EPNODE *
606 getE2(void) /* E2 -> E2 MULOP E3 */
607 /* E3 */
608 {
609 register EPNODE *ep1, *ep2;
610
611 ep1 = getE3();
612 while (nextc == '*' || nextc == '/') {
613 ep2 = newnode();
614 ep2->type = nextc;
615 scan();
616 addekid(ep2, ep1);
617 addekid(ep2, getE3());
618 if (esupport&E_RCONST) {
619 EPNODE *ep3 = ep1->sibling;
620 if (ep1->type == NUM && ep3->type == NUM) {
621 ep2 = rconst(ep2);
622 } else if (ep3->type == NUM && ep3->v.num == 0) {
623 if (ep2->type == '/')
624 syntax("divide by zero constant");
625 ep1->sibling = NULL; /* (E2 * 0) */
626 epfree(ep2);
627 ep2 = ep3;
628 } else if (ep1->type == NUM && ep1->v.num == 0) {
629 epfree(ep3); /* (0 * E3) or (0 / E3) */
630 ep1->sibling = NULL;
631 efree((char *)ep2);
632 ep2 = ep1;
633 }
634 }
635 ep1 = ep2;
636 }
637 return(ep1);
638 }
639
640
641 EPNODE *
642 getE3(void) /* E3 -> E4 ^ E3 */
643 /* E4 */
644 {
645 register EPNODE *ep1, *ep2;
646
647 ep1 = getE4();
648 if (nextc != '^')
649 return(ep1);
650 ep2 = newnode();
651 ep2->type = nextc;
652 scan();
653 addekid(ep2, ep1);
654 addekid(ep2, getE3());
655 if (esupport&E_RCONST) {
656 EPNODE *ep3 = ep1->sibling;
657 if (ep1->type == NUM && ep3->type == NUM) {
658 ep2 = rconst(ep2);
659 } else if (ep1->type == NUM && ep1->v.num == 0) {
660 epfree(ep3); /* (0 ^ E3) */
661 ep1->sibling = NULL;
662 efree((char *)ep2);
663 ep2 = ep1;
664 } else if ((ep3->type == NUM && ep3->v.num == 0) ||
665 (ep1->type == NUM && ep1->v.num == 1)) {
666 epfree(ep2); /* (E4 ^ 0) or (1 ^ E3) */
667 ep2 = newnode();
668 ep2->type = NUM;
669 ep2->v.num = 1;
670 }
671 }
672 return(ep2);
673 }
674
675
676 EPNODE *
677 getE4(void) /* E4 -> ADDOP E5 */
678 /* E5 */
679 {
680 register EPNODE *ep1, *ep2;
681
682 if (nextc == '-') {
683 scan();
684 ep2 = getE5();
685 if (ep2->type == NUM) {
686 ep2->v.num = -ep2->v.num;
687 return(ep2);
688 }
689 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
690 ep1 = ep2->v.kid;
691 efree((char *)ep2);
692 return(ep1);
693 }
694 ep1 = newnode();
695 ep1->type = UMINUS;
696 addekid(ep1, ep2);
697 return(ep1);
698 }
699 if (nextc == '+')
700 scan();
701 return(getE5());
702 }
703
704
705 EPNODE *
706 getE5(void) /* E5 -> (E1) */
707 /* VAR */
708 /* NUM */
709 /* $N */
710 /* FUNC(E1,..) */
711 /* ARG */
712 {
713 int i;
714 char *nam;
715 register EPNODE *ep1, *ep2;
716
717 if (nextc == '(') {
718 scan();
719 ep1 = getE1();
720 if (nextc != ')')
721 syntax("')' expected");
722 scan();
723 return(ep1);
724 }
725
726 if (esupport&E_INCHAN && nextc == '$') {
727 scan();
728 ep1 = newnode();
729 ep1->type = CHAN;
730 ep1->v.chan = getinum();
731 return(ep1);
732 }
733
734 if (esupport&(E_VARIABLE|E_FUNCTION) &&
735 (isalpha(nextc) || nextc == CNTXMARK)) {
736 nam = getname();
737 ep1 = NULL;
738 if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
739 && curfunc != NULL)
740 for (i = 1, ep2 = curfunc->v.kid->sibling;
741 ep2 != NULL; i++, ep2 = ep2->sibling)
742 if (!strcmp(ep2->v.name, nam)) {
743 ep1 = newnode();
744 ep1->type = ARG;
745 ep1->v.chan = i;
746 break;
747 }
748 if (ep1 == NULL) {
749 ep1 = newnode();
750 ep1->type = VAR;
751 ep1->v.ln = varinsert(nam);
752 }
753 if (esupport&E_FUNCTION && nextc == '(') {
754 ep2 = newnode();
755 ep2->type = FUNC;
756 addekid(ep2, ep1);
757 ep1 = ep2;
758 do {
759 scan();
760 addekid(ep1, getE1());
761 } while (nextc == ',');
762 if (nextc != ')')
763 syntax("')' expected");
764 scan();
765 } else if (!(esupport&E_VARIABLE))
766 syntax("'(' expected");
767 if (esupport&E_RCONST && isconstvar(ep1))
768 ep1 = rconst(ep1);
769 return(ep1);
770 }
771
772 if (isdecimal(nextc)) {
773 ep1 = newnode();
774 ep1->type = NUM;
775 ep1->v.num = getnum();
776 return(ep1);
777 }
778 syntax("unexpected character");
779 return NULL; /* pro forma return */
780 }
781
782
783 EPNODE *
784 rconst( /* reduce a constant expression */
785 register EPNODE *epar
786 )
787 {
788 register EPNODE *ep;
789
790 ep = newnode();
791 ep->type = NUM;
792 errno = 0;
793 ep->v.num = evalue(epar);
794 if (errno == EDOM || errno == ERANGE)
795 syntax("bad constant expression");
796 epfree(epar);
797
798 return(ep);
799 }
800
801
802 int
803 isconstvar( /* is ep linked to a constant expression? */
804 register EPNODE *ep
805 )
806 {
807 register EPNODE *ep1;
808
809 if (esupport&E_FUNCTION && ep->type == FUNC) {
810 if (!isconstfun(ep->v.kid))
811 return(0);
812 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
813 if (ep1->type != NUM && !isconstfun(ep1))
814 return(0);
815 return(1);
816 }
817 if (ep->type != VAR)
818 return(0);
819 ep1 = ep->v.ln->def;
820 if (ep1 == NULL || ep1->type != ':')
821 return(0);
822 if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
823 return(0);
824 return(1);
825 }
826
827
828 int
829 isconstfun( /* is ep linked to a constant function? */
830 register EPNODE *ep
831 )
832 {
833 register EPNODE *dp;
834 register LIBR *lp;
835
836 if (ep->type != VAR)
837 return(0);
838 if ((dp = ep->v.ln->def) != NULL) {
839 if (dp->v.kid->type == FUNC)
840 return(dp->type == ':');
841 else
842 return(0); /* don't identify masked library functions */
843 }
844 if ((lp = ep->v.ln->lib) != NULL)
845 return(lp->atyp == ':');
846 return(0);
847 }