ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.33
Committed: Sun Jun 14 18:21:58 2009 UTC (14 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R0
Changes since 2.32: +3 -2 lines
Log Message:
Added ability to specify constant name in rtcontrib -bn option

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calexpr.c,v 2.32 2008/05/01 16:42:05 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 ep1->type == NUM && ep1->sibling->type == NUM)
620 ep2 = rconst(ep2);
621 ep1 = ep2;
622 }
623 return(ep1);
624 }
625
626
627 EPNODE *
628 getE3(void) /* E3 -> E4 ^ E3 */
629 /* E4 */
630 {
631 register EPNODE *ep1, *ep2;
632
633 ep1 = getE4();
634 if (nextc == '^') {
635 ep2 = newnode();
636 ep2->type = nextc;
637 scan();
638 addekid(ep2, ep1);
639 addekid(ep2, getE3());
640 if (esupport&E_RCONST &&
641 ep1->type == NUM && ep1->sibling->type == NUM)
642 ep2 = rconst(ep2);
643 return(ep2);
644 }
645 return(ep1);
646 }
647
648
649 EPNODE *
650 getE4(void) /* E4 -> ADDOP E5 */
651 /* E5 */
652 {
653 register EPNODE *ep1, *ep2;
654
655 if (nextc == '-') {
656 scan();
657 ep2 = getE5();
658 if (ep2->type == NUM) {
659 ep2->v.num = -ep2->v.num;
660 return(ep2);
661 }
662 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
663 ep1 = ep2->v.kid;
664 efree((char *)ep2);
665 return(ep1);
666 }
667 ep1 = newnode();
668 ep1->type = UMINUS;
669 addekid(ep1, ep2);
670 return(ep1);
671 }
672 if (nextc == '+')
673 scan();
674 return(getE5());
675 }
676
677
678 EPNODE *
679 getE5(void) /* E5 -> (E1) */
680 /* VAR */
681 /* NUM */
682 /* $N */
683 /* FUNC(E1,..) */
684 /* ARG */
685 {
686 int i;
687 char *nam;
688 register EPNODE *ep1, *ep2;
689
690 if (nextc == '(') {
691 scan();
692 ep1 = getE1();
693 if (nextc != ')')
694 syntax("')' expected");
695 scan();
696 return(ep1);
697 }
698
699 if (esupport&E_INCHAN && nextc == '$') {
700 scan();
701 ep1 = newnode();
702 ep1->type = CHAN;
703 ep1->v.chan = getinum();
704 return(ep1);
705 }
706
707 if (esupport&(E_VARIABLE|E_FUNCTION) &&
708 (isalpha(nextc) || nextc == CNTXMARK)) {
709 nam = getname();
710 ep1 = NULL;
711 if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
712 && curfunc != NULL)
713 for (i = 1, ep2 = curfunc->v.kid->sibling;
714 ep2 != NULL; i++, ep2 = ep2->sibling)
715 if (!strcmp(ep2->v.name, nam)) {
716 ep1 = newnode();
717 ep1->type = ARG;
718 ep1->v.chan = i;
719 break;
720 }
721 if (ep1 == NULL) {
722 ep1 = newnode();
723 ep1->type = VAR;
724 ep1->v.ln = varinsert(nam);
725 }
726 if (esupport&E_FUNCTION && nextc == '(') {
727 ep2 = newnode();
728 ep2->type = FUNC;
729 addekid(ep2, ep1);
730 ep1 = ep2;
731 do {
732 scan();
733 addekid(ep1, getE1());
734 } while (nextc == ',');
735 if (nextc != ')')
736 syntax("')' expected");
737 scan();
738 } else if (!(esupport&E_VARIABLE))
739 syntax("'(' expected");
740 if (esupport&E_RCONST && isconstvar(ep1))
741 ep1 = rconst(ep1);
742 return(ep1);
743 }
744
745 if (isdecimal(nextc)) {
746 ep1 = newnode();
747 ep1->type = NUM;
748 ep1->v.num = getnum();
749 return(ep1);
750 }
751 syntax("unexpected character");
752 return NULL; /* pro forma return */
753 }
754
755
756 EPNODE *
757 rconst( /* reduce a constant expression */
758 register EPNODE *epar
759 )
760 {
761 register EPNODE *ep;
762
763 ep = newnode();
764 ep->type = NUM;
765 errno = 0;
766 ep->v.num = evalue(epar);
767 if (errno == EDOM || errno == ERANGE)
768 syntax("bad constant expression");
769 epfree(epar);
770
771 return(ep);
772 }
773
774
775 int
776 isconstvar( /* is ep linked to a constant expression? */
777 register EPNODE *ep
778 )
779 {
780 register EPNODE *ep1;
781
782 if (esupport&E_FUNCTION && ep->type == FUNC) {
783 if (!isconstfun(ep->v.kid))
784 return(0);
785 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
786 if (ep1->type != NUM && !isconstfun(ep1))
787 return(0);
788 return(1);
789 }
790 if (ep->type != VAR)
791 return(0);
792 ep1 = ep->v.ln->def;
793 if (ep1 == NULL || ep1->type != ':')
794 return(0);
795 if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
796 return(0);
797 return(1);
798 }
799
800
801 int
802 isconstfun( /* is ep linked to a constant function? */
803 register EPNODE *ep
804 )
805 {
806 register EPNODE *dp;
807 register LIBR *lp;
808
809 if (ep->type != VAR)
810 return(0);
811 if ((dp = ep->v.ln->def) != NULL) {
812 if (dp->v.kid->type == FUNC)
813 return(dp->type == ':');
814 else
815 return(0); /* don't identify masked library functions */
816 }
817 if ((lp = ep->v.ln->lib) != NULL)
818 return(lp->atyp == ':');
819 return(0);
820 }