ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.29
Committed: Sun Mar 28 20:33:12 2004 UTC (20 years ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6, rad3R6P1
Changes since 2.28: +3 -1 lines
Log Message:
Continued ANSIfication, and other fixes and clarifications.

File Contents

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