ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.39
Committed: Sat Dec 28 18:05:13 2019 UTC (4 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.38: +1 -3 lines
Log Message:
Removed redundant include files

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calexpr.c,v 2.38 2019/12/07 16:38:08 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 }
678 }
679 return(ep2);
680 }
681
682
683 EPNODE *
684 getE4(void) /* E4 -> ADDOP E5 */
685 /* E5 */
686 {
687 EPNODE *ep1, *ep2;
688
689 if (nextc == '-') {
690 scan();
691 ep2 = getE5();
692 if (ep2->type == NUM) {
693 ep2->v.num = -ep2->v.num;
694 return(ep2);
695 }
696 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
697 ep1 = ep2->v.kid;
698 efree((char *)ep2);
699 return(ep1);
700 }
701 ep1 = newnode();
702 ep1->type = UMINUS;
703 addekid(ep1, ep2);
704 return(ep1);
705 }
706 if (nextc == '+')
707 scan();
708 return(getE5());
709 }
710
711
712 EPNODE *
713 getE5(void) /* E5 -> (E1) */
714 /* VAR */
715 /* NUM */
716 /* $N */
717 /* FUNC(E1,..) */
718 /* ARG */
719 {
720 int i;
721 char *nam;
722 EPNODE *ep1, *ep2;
723
724 if (nextc == '(') {
725 scan();
726 ep1 = getE1();
727 if (nextc != ')')
728 syntax("')' expected");
729 scan();
730 return(ep1);
731 }
732
733 if (esupport&E_INCHAN && nextc == '$') {
734 scan();
735 ep1 = newnode();
736 ep1->type = CHAN;
737 ep1->v.chan = getinum();
738 return(ep1);
739 }
740
741 if (esupport&(E_VARIABLE|E_FUNCTION) &&
742 (isalpha(nextc) || nextc == CNTXMARK)) {
743 nam = getname();
744 ep1 = NULL;
745 if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
746 && curfunc != NULL)
747 for (i = 1, ep2 = curfunc->v.kid->sibling;
748 ep2 != NULL; i++, ep2 = ep2->sibling)
749 if (!strcmp(ep2->v.name, nam)) {
750 ep1 = newnode();
751 ep1->type = ARG;
752 ep1->v.chan = i;
753 break;
754 }
755 if (ep1 == NULL) {
756 ep1 = newnode();
757 ep1->type = VAR;
758 ep1->v.ln = varinsert(nam);
759 }
760 if (esupport&E_FUNCTION && nextc == '(') {
761 ep2 = newnode();
762 ep2->type = FUNC;
763 addekid(ep2, ep1);
764 ep1 = ep2;
765 do {
766 scan();
767 addekid(ep1, getE1());
768 } while (nextc == ',');
769 if (nextc != ')')
770 syntax("')' expected");
771 scan();
772 } else if (!(esupport&E_VARIABLE))
773 syntax("'(' expected");
774 if (esupport&E_RCONST && isconstvar(ep1))
775 ep1 = rconst(ep1);
776 return(ep1);
777 }
778
779 if (isdecimal(nextc)) {
780 ep1 = newnode();
781 ep1->type = NUM;
782 ep1->v.num = getnum();
783 return(ep1);
784 }
785 syntax("unexpected character");
786 return NULL; /* pro forma return */
787 }
788
789
790 EPNODE *
791 rconst( /* reduce a constant expression */
792 EPNODE *epar
793 )
794 {
795 EPNODE *ep;
796
797 ep = newnode();
798 ep->type = NUM;
799 errno = 0;
800 ep->v.num = evalue(epar);
801 if (errno == EDOM || errno == ERANGE)
802 syntax("bad constant expression");
803 epfree(epar);
804
805 return(ep);
806 }
807
808
809 int
810 isconstvar( /* is ep linked to a constant expression? */
811 EPNODE *ep
812 )
813 {
814 EPNODE *ep1;
815
816 if (esupport&E_FUNCTION && ep->type == FUNC) {
817 if (!isconstfun(ep->v.kid))
818 return(0);
819 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
820 if (ep1->type != NUM && !isconstfun(ep1))
821 return(0);
822 return(1);
823 }
824 if (ep->type != VAR)
825 return(0);
826 ep1 = ep->v.ln->def;
827 if (ep1 == NULL || ep1->type != ':')
828 return(0);
829 if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
830 return(0);
831 return(1);
832 }
833
834
835 int
836 isconstfun( /* is ep linked to a constant function? */
837 EPNODE *ep
838 )
839 {
840 EPNODE *dp;
841 LIBR *lp;
842
843 if (ep->type != VAR)
844 return(0);
845 if ((dp = ep->v.ln->def) != NULL) {
846 if (dp->v.kid->type == FUNC)
847 return(dp->type == ':');
848 else
849 return(0); /* don't identify masked library functions */
850 }
851 if ((lp = ep->v.ln->lib) != NULL)
852 return(lp->atyp == ':');
853 return(0);
854 }