ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.28
Committed: Fri Nov 14 17:22:06 2003 UTC (20 years, 5 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.27: +95 -69 lines
Log Message:
Reduced compile warnings, and other compatibility fixes.

File Contents

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