ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.24
Committed: Thu Jul 17 09:21:29 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.23: +8 -5 lines
Log Message:
Added prototypes and includes from patch by Randolph Fritz.
Added more required includes and reduced other compile warnings.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calexpr.c,v 2.23 2003/07/03 22:41:44 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 "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[])() = { /* 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 return 0.0; /* pro forma return */
299 }
300
301
302 EPNODE *
303 ekid(ep, n) /* return pointer to a node's nth kid */
304 register EPNODE *ep;
305 register int n;
306 {
307
308 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
309 if (--n < 0)
310 break;
311
312 return(ep);
313 }
314
315
316 int
317 nekids(ep) /* return # of kids for node ep */
318 register EPNODE *ep;
319 {
320 register int n = 0;
321
322 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
323 n++;
324
325 return(n);
326 }
327
328
329 void
330 initfile(fp, fn, ln) /* prepare input file */
331 FILE *fp;
332 char *fn;
333 int ln;
334 {
335 static char inpbuf[MAXLINE];
336
337 infp = fp;
338 linbuf = inpbuf;
339 infile = fn;
340 lineno = ln;
341 linepos = 0;
342 inpbuf[0] = '\0';
343 scan();
344 }
345
346
347 void
348 initstr(s, fn, ln) /* prepare input string */
349 char *s;
350 char *fn;
351 int ln;
352 {
353 infp = NULL;
354 infile = fn;
355 lineno = ln;
356 linbuf = s;
357 linepos = 0;
358 scan();
359 }
360
361
362 void
363 getscanpos(fnp, lnp, spp, fpp) /* return current scan position */
364 char **fnp;
365 int *lnp;
366 char **spp;
367 FILE **fpp;
368 {
369 if (fnp != NULL) *fnp = infile;
370 if (lnp != NULL) *lnp = lineno;
371 if (spp != NULL) *spp = linbuf+linepos;
372 if (fpp != NULL) *fpp = infp;
373 }
374
375
376 int
377 scan() /* scan next character, return literal next */
378 {
379 register int lnext = 0;
380
381 do {
382 if (linbuf[linepos] == '\0')
383 if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
384 nextc = EOF;
385 else {
386 nextc = linbuf[0];
387 lineno++;
388 linepos = 1;
389 }
390 else
391 nextc = linbuf[linepos++];
392 if (!lnext)
393 lnext = nextc;
394 if (nextc == '{') {
395 scan();
396 while (nextc != '}')
397 if (nextc == EOF)
398 syntax("'}' expected");
399 else
400 scan();
401 scan();
402 }
403 } while (isspace(nextc));
404 return(lnext);
405 }
406
407
408 char *
409 long2ascii(l) /* convert long to ascii */
410 long l;
411 {
412 static char buf[16];
413 register char *cp;
414 int neg = 0;
415
416 if (l == 0)
417 return("0");
418 if (l < 0) {
419 l = -l;
420 neg++;
421 }
422 cp = buf + sizeof(buf);
423 *--cp = '\0';
424 while (l) {
425 *--cp = l % 10 + '0';
426 l /= 10;
427 }
428 if (neg)
429 *--cp = '-';
430 return(cp);
431 }
432
433
434 void
435 syntax(err) /* report syntax error and quit */
436 char *err;
437 {
438 register int i;
439
440 if (infile != NULL || lineno != 0) {
441 if (infile != NULL) eputs(infile);
442 if (lineno != 0) {
443 eputs(infile != NULL ? ", line " : "line ");
444 eputs(long2ascii((long)lineno));
445 }
446 eputs(":\n");
447 }
448 eputs(linbuf);
449 if (linbuf[strlen(linbuf)-1] != '\n')
450 eputs("\n");
451 for (i = 0; i < linepos-1; i++)
452 eputs(linbuf[i] == '\t' ? "\t" : " ");
453 eputs("^ ");
454 eputs(err);
455 eputs("\n");
456 quit(1);
457 }
458
459
460 void
461 addekid(ep, ekid) /* add a child to ep */
462 register EPNODE *ep;
463 EPNODE *ekid;
464 {
465 if (ep->v.kid == NULL)
466 ep->v.kid = ekid;
467 else {
468 for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
469 ;
470 ep->sibling = ekid;
471 }
472 ekid->sibling = NULL;
473 }
474
475
476 char *
477 getname() /* scan an identifier */
478 {
479 static char str[RMAXWORD+1];
480 register int i, lnext;
481
482 lnext = nextc;
483 for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = scan())
484 str[i] = lnext;
485 str[i] = '\0';
486 while (isid(lnext)) /* skip rest of name */
487 lnext = scan();
488
489 return(str);
490 }
491
492
493 int
494 getinum() /* scan a positive integer */
495 {
496 register int n, lnext;
497
498 n = 0;
499 lnext = nextc;
500 while (isdigit(lnext)) {
501 n = n * 10 + lnext - '0';
502 lnext = scan();
503 }
504 return(n);
505 }
506
507
508 double
509 getnum() /* scan a positive float */
510 {
511 register int i, lnext;
512 char str[RMAXWORD+1];
513
514 i = 0;
515 lnext = nextc;
516 while (isdigit(lnext) && i < RMAXWORD) {
517 str[i++] = lnext;
518 lnext = scan();
519 }
520 if (lnext == '.' && i < RMAXWORD) {
521 str[i++] = lnext;
522 lnext = scan();
523 if (i == 1 && !isdigit(lnext))
524 syntax("badly formed number");
525 while (isdigit(lnext) && i < RMAXWORD) {
526 str[i++] = lnext;
527 lnext = scan();
528 }
529 }
530 if ((lnext == 'e' | lnext == 'E') && i < RMAXWORD) {
531 str[i++] = lnext;
532 lnext = scan();
533 if ((lnext == '-' | lnext == '+') && i < RMAXWORD) {
534 str[i++] = lnext;
535 lnext = scan();
536 }
537 if (!isdigit(lnext))
538 syntax("missing exponent");
539 while (isdigit(lnext) && i < RMAXWORD) {
540 str[i++] = lnext;
541 lnext = scan();
542 }
543 }
544 str[i] = '\0';
545
546 return(atof(str));
547 }
548
549
550 EPNODE *
551 getE1() /* E1 -> E1 ADDOP E2 */
552 /* E2 */
553 {
554 register EPNODE *ep1, *ep2;
555
556 ep1 = getE2();
557 while (nextc == '+' || nextc == '-') {
558 ep2 = newnode();
559 ep2->type = nextc;
560 scan();
561 addekid(ep2, ep1);
562 addekid(ep2, getE2());
563 if (esupport&E_RCONST &&
564 ep1->type == NUM && ep1->sibling->type == NUM)
565 ep2 = rconst(ep2);
566 ep1 = ep2;
567 }
568 return(ep1);
569 }
570
571
572 EPNODE *
573 getE2() /* E2 -> E2 MULOP E3 */
574 /* E3 */
575 {
576 register EPNODE *ep1, *ep2;
577
578 ep1 = getE3();
579 while (nextc == '*' || nextc == '/') {
580 ep2 = newnode();
581 ep2->type = nextc;
582 scan();
583 addekid(ep2, ep1);
584 addekid(ep2, getE3());
585 if (esupport&E_RCONST &&
586 ep1->type == NUM && ep1->sibling->type == NUM)
587 ep2 = rconst(ep2);
588 ep1 = ep2;
589 }
590 return(ep1);
591 }
592
593
594 EPNODE *
595 getE3() /* E3 -> E4 ^ E3 */
596 /* E4 */
597 {
598 register EPNODE *ep1, *ep2;
599
600 ep1 = getE4();
601 if (nextc == '^') {
602 ep2 = newnode();
603 ep2->type = nextc;
604 scan();
605 addekid(ep2, ep1);
606 addekid(ep2, getE3());
607 if (esupport&E_RCONST &&
608 ep1->type == NUM && ep1->sibling->type == NUM)
609 ep2 = rconst(ep2);
610 return(ep2);
611 }
612 return(ep1);
613 }
614
615
616 EPNODE *
617 getE4() /* E4 -> ADDOP E5 */
618 /* E5 */
619 {
620 register EPNODE *ep1, *ep2;
621
622 if (nextc == '-') {
623 scan();
624 ep2 = getE5();
625 if (ep2->type == NUM) {
626 ep2->v.num = -ep2->v.num;
627 return(ep2);
628 }
629 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
630 efree((char *)ep2);
631 return(ep2->v.kid);
632 }
633 ep1 = newnode();
634 ep1->type = UMINUS;
635 addekid(ep1, ep2);
636 return(ep1);
637 }
638 if (nextc == '+')
639 scan();
640 return(getE5());
641 }
642
643
644 EPNODE *
645 getE5() /* E5 -> (E1) */
646 /* VAR */
647 /* NUM */
648 /* $N */
649 /* FUNC(E1,..) */
650 /* ARG */
651 {
652 int i;
653 char *nam;
654 register EPNODE *ep1, *ep2;
655
656 if (nextc == '(') {
657 scan();
658 ep1 = getE1();
659 if (nextc != ')')
660 syntax("')' expected");
661 scan();
662 return(ep1);
663 }
664
665 if (esupport&E_INCHAN && nextc == '$') {
666 scan();
667 ep1 = newnode();
668 ep1->type = CHAN;
669 ep1->v.chan = getinum();
670 return(ep1);
671 }
672
673 if (esupport&(E_VARIABLE|E_FUNCTION) &&
674 (isalpha(nextc) || nextc == CNTXMARK)) {
675 nam = getname();
676 ep1 = NULL;
677 if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
678 && curfunc != NULL)
679 for (i = 1, ep2 = curfunc->v.kid->sibling;
680 ep2 != NULL; i++, ep2 = ep2->sibling)
681 if (!strcmp(ep2->v.name, nam)) {
682 ep1 = newnode();
683 ep1->type = ARG;
684 ep1->v.chan = i;
685 break;
686 }
687 if (ep1 == NULL) {
688 ep1 = newnode();
689 ep1->type = VAR;
690 ep1->v.ln = varinsert(nam);
691 }
692 if (esupport&E_FUNCTION && nextc == '(') {
693 ep2 = newnode();
694 ep2->type = FUNC;
695 addekid(ep2, ep1);
696 ep1 = ep2;
697 do {
698 scan();
699 addekid(ep1, getE1());
700 } while (nextc == ',');
701 if (nextc != ')')
702 syntax("')' expected");
703 scan();
704 } else if (!(esupport&E_VARIABLE))
705 syntax("'(' expected");
706 if (esupport&E_RCONST && isconstvar(ep1))
707 ep1 = rconst(ep1);
708 return(ep1);
709 }
710
711 if (isdecimal(nextc)) {
712 ep1 = newnode();
713 ep1->type = NUM;
714 ep1->v.num = getnum();
715 return(ep1);
716 }
717 syntax("unexpected character");
718 return NULL; /* pro forma return */
719 }
720
721
722 EPNODE *
723 rconst(epar) /* reduce a constant expression */
724 register EPNODE *epar;
725 {
726 register EPNODE *ep;
727
728 ep = newnode();
729 ep->type = NUM;
730 errno = 0;
731 ep->v.num = evalue(epar);
732 if (errno == EDOM || errno == ERANGE)
733 syntax("bad constant expression");
734 epfree(epar);
735
736 return(ep);
737 }
738
739
740 int
741 isconstvar(ep) /* is ep linked to a constant expression? */
742 register EPNODE *ep;
743 {
744 register EPNODE *ep1;
745
746 if (esupport&E_FUNCTION && ep->type == FUNC) {
747 if (!isconstfun(ep->v.kid))
748 return(0);
749 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
750 if (ep1->type != NUM && !isconstfun(ep1))
751 return(0);
752 return(1);
753 }
754 if (ep->type != VAR)
755 return(0);
756 ep1 = ep->v.ln->def;
757 if (ep1 == NULL || ep1->type != ':')
758 return(0);
759 if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
760 return(0);
761 return(1);
762 }
763
764
765 int
766 isconstfun(ep) /* is ep linked to a constant function? */
767 register EPNODE *ep;
768 {
769 register EPNODE *dp;
770 register LIBR *lp;
771
772 if (ep->type != VAR)
773 return(0);
774 if ((dp = ep->v.ln->def) != NULL)
775 if (dp->v.kid->type == FUNC)
776 return(dp->type == ':');
777 else
778 return(0); /* don't identify masked library functions */
779 if ((lp = ep->v.ln->lib) != NULL)
780 return(lp->atyp == ':');
781 return(0);
782 }