ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.21
Committed: Mon Jun 2 18:13:54 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.20: +1 -1 lines
Log Message:
Turned off E_REDEFW by default

File Contents

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