ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.16
Committed: Thu Feb 16 09:49:29 1995 UTC (29 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.15: +47 -0 lines
Log Message:
made redefinition warnings more intelligent --
won't report new definitions that are equivalent to old

File Contents

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