ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.40
Committed: Fri Jun 19 22:33:45 2020 UTC (3 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.39: +6 -1 lines
Log Message:
Added reduction for (E4)^1

File Contents

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